diff --git a/README.md b/README.md index 264d02c..ad86d29 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,7 @@ Click on the desired API to see usage and more information * [Recipient Lists](/docs/resources/recipientLists.md) - `client.recipientLists` ([examples](/examples/recipientLists)) * [Relay Webhooks](/docs/resources/relayWebhooks.md) - `client.relayWebhooks` ([examples](/examples/relayWebhooks)) * [Sending Domains](/docs/resources/sendingDomains.md) - `client.sendingDomains` ([examples](/examples/sendingDomains)) +* [Subaccounts](/docs/resources/subaccounts.md) - `client.subaccounts` ([examples](/examples/subaccounts)) * [Suppression List](/docs/resources/suppressionList.md) - `client.suppressionList` ([examples](/examples/suppressionList)) * [Templates](/docs/resources/templates.md) - `client.templates` ([examples](/examples/templates)) * [Transmissions](/docs/resources/transmissions.md) - `client.transmissions` ([examples](/examples/transmissions)) diff --git a/docs/resources/subaccounts.md b/docs/resources/subaccounts.md new file mode 100644 index 0000000..d948692 --- /dev/null +++ b/docs/resources/subaccounts.md @@ -0,0 +1,46 @@ +# Subaccounts + +This library provides easy access to the [Subaccounts](https://www.sparkpost.com/api#/reference/subaccounts) Resource. + +## Methods +* **all(callback)** + List a summary of all subaccounts. + * `callback` - executed after task is completed. **required** + * standard `callback(err, data)` + * `err` - any error that occurred + * `data` - full response from request client +* **find(subaccountId, callback)** + Retrieve details about a specified subaccount by its id + * `subaccountId` - the id of the subaccount you want to look up **required** + * `callback` - see all function +* **create(options, callback)** + Create a new subaccount + * `options.name` - user-friendly name **required** + * `options.keyLabel` - user-friendly identifier for subaccount API key **required** + * `options.keyGrants` - list of grants to give the subaccount API key **required** + * `options.keyValidIps` - list of IPs the subaccount may be used from + * `options.ipPool` - id of the default IP pool assigned to subaccount's transmissions + * `callback` - see all function +* **update(options, callback)** + Updates an existing subaccount + * `options.subaccountId` - the id of the subaccount you want to update **required** + * `options.name` - user-friendly name + * `options.status` - status of the subaccount + * `options.ipPool` - id of the default IP pool assigned to subaccount's transmissions + * `callback` - see all function + +## Examples + +```js +var SparkPost = require('sparkpost'); +var client = new SparkPost('YOUR_API_KEY'); + +client.subaccounts.all(function(err, data) { + if(err) { + console.log(err); + return; + } + + console.log(data.body); +}); +``` diff --git a/lib/subaccounts.js b/lib/subaccounts.js new file mode 100644 index 0000000..888a2a6 --- /dev/null +++ b/lib/subaccounts.js @@ -0,0 +1,108 @@ +'use strict'; + +var api = 'subaccounts'; + +var toApiFormat = function(input) { + var model = {}; + + model.name = input.name; + model.key_label = input.keyLabel; + model.ip_pool = input.ipPool; + model.status = input.status; + + model.key_grants = Array.isArray(input.keyGrants) ? input.keyGrants : [input.keyGrants]; + model.key_valid_ips = Array.isArray(input.keyValidIps) ? input.keyValidIps : [input.keyValidIps]; + + return model; +}; + +var validateCreateOptions = function(input) { + if (!input.name) { + return 'name is required'; + } + + if (!input.keyLabel) { + return 'keyLabel is required'; + } + + if (!input.keyGrants) { + return 'keyGrants is required'; + } + + return null; +}; + +module.exports = function(client) { + var subaccounts = { + all: function(callback) { + var options = { + uri: api + }; + client.get(options, callback); + }, + find: function(subaccountId, callback) { + if(typeof subaccountId === 'function') { + callback = subaccountId; + subaccountId = null; + } + + if (!subaccountId) { + callback(new Error('subaccountId is required')); + return; + } + + var options = { + uri: api + '/' + subaccountId + }; + client.get(options, callback); + }, + create: function(options, callback) { + if(typeof options === 'function') { + callback = options; + options = null; + } + + if (!options) { + callback(new Error('options are required')); + return; + } + + var validation = validateCreateOptions(options); + if (validation) { + callback(new Error(validation + ' in options')); + return; + } + + var reqOpts = { + uri: api, + json: toApiFormat(options) + }; + client.post(reqOpts, callback); + }, + update: function(options, callback) { + if(typeof options === 'function') { + callback = options; + options = null; + } + + if(!options) { + callback(new Error('options are required')); + return; + } + + if(!options.subaccountId) { + callback(new Error('subaccountId is required in options')); + return; + } + + var subaccountId = options.subaccountId; + var reqOpts = { + uri: api + '/' + subaccountId, + json: toApiFormat(options) + }; + client.put(reqOpts, callback); + } + }; + + return subaccounts; +}; diff --git a/test/spec/subaccounts.spec.js b/test/spec/subaccounts.spec.js new file mode 100644 index 0000000..a69f804 --- /dev/null +++ b/test/spec/subaccounts.spec.js @@ -0,0 +1,165 @@ +var chai = require('chai') + , expect = chai.expect + , sinon = require('sinon') + , sinonChai = require('sinon-chai'); + +chai.use(sinonChai); + +describe('Subaccounts Library', function () { + var client, subaccounts; + + beforeEach(function() { + client = { + get: sinon.stub().yields(), + post: sinon.stub().yields(), + put: sinon.stub().yields() + }; + + subaccounts = require('../../lib/subaccounts')(client); + }); + + describe('all Method', function() { + it('should call client get method with the appropriate uri', function(done) { + subaccounts.all(function(err, data) { + expect(client.get.firstCall.args[0].uri).to.equal('subaccounts'); + done(); + }); + }); + }); + + describe('find Method', function() { + it('should call client get method with the appropriate uri', function(done) { + var subaccountId = 'test'; + + subaccounts.find(subaccountId, function(err, data) { + expect(client.get.firstCall.args[0].uri).to.equal('subaccounts/test'); + done(); + }); + }); + + it('should throw an error if subaccountId is null', function(done) { + subaccounts.find(null, function(err) { + expect(err.message).to.equal('subaccountId is required'); + expect(client.get).not.to.have.been.called; + done(); + }); + }); + + it('should throw an error if subaccountId is missing', function(done) { + subaccounts.find(function(err) { + expect(err.message).to.equal('subaccountId is required'); + expect(client.get).not.to.have.been.called; + done(); + }); + }); + }); + + describe('create Method', function() { + it('should call client post method with the appropriate uri', function(done) { + var options = { + name: 'test', + keyLabel: 'test', + keyGrants: [] + }; + + subaccounts.create(options, function(err, data) { + expect(client.post.firstCall.args[0].uri).to.equal('subaccounts'); + done(); + }); + }); + + it('should throw an error if options is null', function(done) { + subaccounts.create(null, function(err) { + expect(err.message).to.equal('options are required'); + expect(client.post).not.to.have.been.called; + done(); + }); + }); + + it('should throw an error if options is missing', function(done) { + subaccounts.create(function(err) { + expect(err.message).to.equal('options are required'); + expect(client.post).not.to.have.been.called; + done(); + }); + }); + + it('should throw an error if name is missing from options', function(done) { + var options = { + keyLabel: 'test', + keyGrants: [] + }; + + subaccounts.create(options, function(err) { + expect(err.message).to.equal('name is required in options'); + expect(client.post).not.to.have.been.called; + done(); + }); + }); + + it('should throw an error if keyLabel is missing from options', function(done) { + var options = { + name: 'test', + keyGrants: [] + }; + + subaccounts.create(options, function(err) { + expect(err.message).to.equal('keyLabel is required in options'); + expect(client.post).not.to.have.been.called; + done(); + }); + }); + + it('should throw an error if keyGrants is missing from options', function(done) { + var options = { + name: 'test', + keyLabel: 'test' + }; + + subaccounts.create(options, function(err) { + expect(err.message).to.equal('keyGrants is required in options'); + expect(client.post).not.to.have.been.called; + done(); + }); + }); + }); + + describe('update Method', function() { + it('should call client put method with the appropriate uri', function(done) { + var options = { + subaccountId: 'test' + }; + + subaccounts.update(options, function(err, data) { + expect(client.put.firstCall.args[0].uri).to.equal('subaccounts/test'); + done(); + }); + }); + + it('should throw an error if options is null', function(done) { + subaccounts.update(null, function(err) { + expect(err.message).to.equal('options are required'); + expect(client.put).not.to.have.been.called; + done(); + }); + }); + + it('should throw an error if options is missing', function(done) { + subaccounts.update(function(err) { + expect(err.message).to.equal('options are required'); + expect(client.put).not.to.have.been.called; + done(); + }); + }); + + it('should throw an error if subaccountId is missing from options', function(done) { + var options = {}; + + subaccounts.update(options, function(err, data) { + expect(err.message).to.equal('subaccountId is required in options'); + expect(client.put).not.to.have.been.called; + done(); + }); + }); + }); +});