diff --git a/lib/resource/Application.js b/lib/resource/Application.js index 43f02038..3a0128e5 100644 --- a/lib/resource/Application.js +++ b/lib/resource/Application.js @@ -1503,4 +1503,17 @@ Application.prototype.getAccountLinkingPolicy = function getApplicationAccountLi return this.dataStore.getResource(this.accountLinkingPolicy.href, args.options, require('./AccountLinkingPolicy'), args.callback); }; +/** + * Retrieves the application's {@link WebConfig}, which determines its behaviour + * regarding the Client API. + * + * @param {Function} callback + * The function that will be called when the query is finished, with the parameters + * (err, {@link WebConfig}). + */ +Application.prototype.getWebConfig = function getApplicationWebConfig(/* callback */) { + var args = utils.resolveArgs(arguments, ['callback'], true); + return this.dataStore.getResource(this.webConfig.href, null, require('./WebConfig'), args.callback); +}; + module.exports = Application; diff --git a/lib/resource/WebConfig.js b/lib/resource/WebConfig.js new file mode 100644 index 00000000..99843ef9 --- /dev/null +++ b/lib/resource/WebConfig.js @@ -0,0 +1,78 @@ +'use strict'; + +var InstanceResource = require('./InstanceResource'); +var utils = require('../utils'); + +/** + * @class WebConfig + * + * @augments {InstanceResource} + * + * @description + * + * Encapsulates a WebConfig resource, which determines the behaviour of the + * web application used for the Client API. For full documentation of this + * resource, please see + * [Configuring the Client API](https://docs.stormpath.com/client-api/product-guide/latest/configuration.html). + * + * This class should not be manually constructed. It should be obtained from one + * of these methods: + * + * - {@link Application#getWebConfig Application.getWebConfig()}. + * + * @param {Object} webConfigResource + * + * The JSON representation of this resource. + */ +function WebConfig() { + WebConfig.super_.apply(this, arguments); +} + +utils.inherits(WebConfig, InstanceResource); + +/** + * Retrieves the {@link Application} that this web configuration is attached to. + * + * @param {ExpansionOptions} options + * Options for retrieving the linked resources of the application. + * + * @param {Function} callback + * The function to call after the query has completed. It will be called with + * (err, {@link Application}). + */ +WebConfig.prototype.getApplication = function getWebConfigApplication(/* [options], callback */) { + var args = utils.resolveArgs(arguments, ['options', 'callback'], true); + return this.dataStore.getResource(this.application.href, args.options, require('./Application'), args.callback); +}; + +/** + * Retrieves the {@link ApiKey} that this web config is using for signing tokens. + * + * @param {Options} options + * Options for retrieving the linked resources of the API Key. + * + * @param {Function} callback + * The function to call after the query has completed. It will be called with + * (err, {@link ApiKey}). + */ +WebConfig.prototype.getSigningApiKey = function getSigningApiKey(/* [options], callback */) { + var args = utils.resolveArgs(arguments, ['options', 'callback'], true); + return this.dataStore.getResource(this.signingApiKey.href, args.options, require('./ApiKey'), args.callback); +}; + +/** + * Retrieves the {@link Tenant} for this web configuration. + * + * @param {ExpansionOptions} options + * Options for retrieving the linked resources of the tenant. + * + * @param {Function} callback + * The function to call after the query has completed. It will be called with + * (err, {@link Tenant}). + */ +WebConfig.prototype.getTenant = function getWebConfigTenant(/* [options], callback */) { + var args = utils.resolveArgs(arguments, ['options', 'callback'], true); + return this.dataStore.getResource(this.tenant.href, args.options, require('./Tenant'), args.callback); +}; + +module.exports = WebConfig; \ No newline at end of file diff --git a/test/it/web_config_it.js b/test/it/web_config_it.js new file mode 100644 index 00000000..544fe7f6 --- /dev/null +++ b/test/it/web_config_it.js @@ -0,0 +1,97 @@ +'use strict'; + +var common = require('../common'); +var helpers = require('./helpers'); +var assert = common.assert; + +var WebConfig = require('../../lib/resource/WebConfig'); + +describe('WebConfig', function() { + var client; + var app; + var webConfig; + var signingKey; + + before(function(done) { + helpers.getClient(function(_client) { + client = _client; + signingKey = client._dataStore.requestExecutor.options.client.apiKey.secret; + + client.createApplication({ name: helpers.uniqId()}, function(err, _app) { + if (err) { + return done(err); + } + + app = _app; + app.getWebConfig(function(err, _webConfig) { + if (err) { + return done(err); + } + + webConfig = _webConfig; + done(); + }); + }); + }); + }); + + after(function(done) { + app.delete(function(err) { + if (err) { + return done(err); + } + + done(); + }); + }); + + it('should be get-able', function() { + assert.instanceOf(webConfig, WebConfig); + }); + + it('should have the application uri', function() { + assert.isOk(webConfig.dnsLabel); + }); + + it('should be possible to enable it', function(done) { + webConfig.status = 'ENABLED'; + + webConfig.save(function(err, _webConfig) { + if (err) { + return done(err); + } + + assert.equal(_webConfig.status, 'ENABLED'); + done(); + }); + }); + + it('should be possible to disable it', function(done) { + webConfig.status = 'DISABLED'; + + webConfig.save(function(err, _webConfig) { + if (err) { + return done(err); + } + + assert.equal(_webConfig.status, 'DISABLED'); + done(); + }); + }); + + it('should be possible to edit it', function(done) { + var oldRegisterStatus = webConfig.register.enabled; + var newRegisterStatus = !oldRegisterStatus; + + webConfig.register.enabled = newRegisterStatus; + + webConfig.save(function(err, _webConfig) { + if (err) { + return done(err); + } + + assert.equal(_webConfig.register.enabled, newRegisterStatus); + done(); + }); + }); +}); \ No newline at end of file diff --git a/test/sp.resource.application_test.js b/test/sp.resource.application_test.js index 3f7510d5..8c129658 100644 --- a/test/sp.resource.application_test.js +++ b/test/sp.resource.application_test.js @@ -19,6 +19,7 @@ var ApiKey = require('../lib/resource/ApiKey'); var DataStore = require('../lib/ds/DataStore'); var PasswordResetToken = require('../lib/resource/PasswordResetToken'); var AccountLinkingPolicy = require('../lib/resource/AccountLinkingPolicy'); +var WebConfig = require('../lib/resource/WebConfig'); var nJwt = require('njwt'); var nJwtProperties = require('njwt/properties'); var uuid = require('uuid'); @@ -1501,5 +1502,39 @@ describe('Resources: ', function () { }); }); + describe('get web config', function () { + var sandbox, application, getResourceStub, cbSpy, app; + before(function () { + sandbox = sinon.sandbox.create(); + app = { + webConfig: { + href: 'boom!' + } + }; + + application = new Application(app, dataStore); + getResourceStub = sandbox.stub(dataStore, 'getResource', function (href, options, ctor, cb) { + cb(); + }); + cbSpy = sandbox.spy(); + + application.getWebConfig(cbSpy); + }); + + after(function () { + sandbox.restore(); + }); + + it('should get the web config', function () { + /* jshint -W030 */ + getResourceStub.should.have.been.calledOnce; + cbSpy.should.have.been.calledOnce; + /* jshint +W030 */ + + getResourceStub.should.have.been + .calledWith(app.webConfig.href, null, WebConfig, cbSpy); + }); + }); + }); }); diff --git a/test/sp.resource.webConfig_test.js b/test/sp.resource.webConfig_test.js new file mode 100644 index 00000000..cccfa261 --- /dev/null +++ b/test/sp.resource.webConfig_test.js @@ -0,0 +1,258 @@ +'use strict'; + +var common = require('./common'); +var assert = common.assert; +var sinon = common.sinon; + +var ApiKey = require('../lib/resource/ApiKey'); +var Application = require('../lib/resource/Application'); +var DataStore = require('../lib/ds/DataStore'); +var InstanceResource = require('../lib/resource/InstanceResource'); +var Tenant = require('../lib/resource/Tenant'); +var WebConfig = require('../lib/resource/WebConfig'); + +var webConfigData = { + href: 'https://api.stormpath.com/v1/applicationWebConfigs/14wIJqPVADzqMfjcY7DJ2p', + createdAt: '2016-11-11T04:27:21.688Z', + modifiedAt: '2016-12-13T14:20:02.958Z', + dnsLabel: 'example-application', + domainName: 'example-application.apps.stormpath.io', + status: 'ENABLED', + oauth2: { + enabled: true + }, + register: { + enabled: true + }, + login: { + enabled: true + }, + verifyEmail: { + enabled: true + }, + forgotPassword: { + enabled: null + }, + changePassword: { + enabled: null + }, + me: { + enabled: true, + expand: { + providerData: false, + applications: false, + apiKeys: false, + customData: false, + groups: false, + groupMemberships: false, + directory: false, + tenant: true + } + }, + signingApiKey: { + href: 'https://api.stormpath.com/v1/apiKeys/3NQKZ6CLAE1QJAQFDS9B3WT81' + }, + application: { + href: 'https://api.stormpath.com/v1/applications/2jalCiSk81m0jjFCzQPVb8' + }, + tenant: { + href: 'https://api.stormpath.com/v1/tenants/3BDwQnZM0rtp1VJ0rWE8IC' + } +}; + +describe('WebConfig resource', function() { + var opts; + + before(function() { + opts = {expand: 'something'}; + }); + + describe('constructor', function() { + var superSpy; + var sandbox; + var dataStore; + var webConfig; + + before(function() { + dataStore = new DataStore({client: {apiKey: {id: 1, secret: 2}}}); + webConfig = new WebConfig(webConfigData, dataStore); + sandbox = sinon.sandbox.create(); + superSpy = sandbox.spy(WebConfig, 'super_'); + + new WebConfig(webConfigData, dataStore); + }); + + after(function() { + sandbox.restore(); + }); + + it('should call super_ with the same arguments', function() { + /*jshint -W030 */ + superSpy.should.have.been.calledOnce; + superSpy.should.have.been.calledWithExactly(webConfigData, dataStore); + /*jshint +W030 */ + }); + }); + + describe('instantiation and inheritance', function() { + var dataStore; + var webConfig; + + before(function() { + dataStore = new DataStore({client: {apiKey: {id: 1, secret: 2}}}); + webConfig = new WebConfig(webConfigData, dataStore); + }); + + it('should inherit from InstanceResource', function() { + assert.instanceOf(webConfig, InstanceResource); + }); + + it('should be an instance of WebConfig', function() { + assert.instanceOf(webConfig, WebConfig); + }); + }); + + describe('#getApplication(options, callback)', function() { + var callback; + var getResourceStub; + var sandbox; + var dataStore; + var webConfig; + + before(function() { + dataStore = new DataStore({client: {apiKey: {id: 1, secret: 2}}}); + webConfig = new WebConfig(webConfigData, dataStore); + sandbox = sinon.sandbox.create(); + getResourceStub = sinon.stub(dataStore, 'getResource'); + callback = sinon.spy(); + webConfig.getApplication(callback); + webConfig.getApplication(opts, callback); + }); + + after(function() { + sandbox.restore(); + }); + + it('should call dataStore#getResource', function() { + /*jshint -W030 */ + getResourceStub.should.have.been.calledTwice; + /*jshint +W030 */ + }); + + it('should pass the correct href to dataStore#getResource', function() { + getResourceStub.args[0][0].should.equal(webConfigData.application.href); + getResourceStub.args[1][0].should.equal(webConfigData.application.href); + }); + + it('should pass expansion options, if passed, to dataStore#getResource', function() { + assert.isNotOk(getResourceStub.args[0][1]); + getResourceStub.args[1][1].should.equal(opts); + }); + + it('should pass the constructor for Application to dataStore#getResource', function() { + getResourceStub.args[0][2].should.equal(Application); + getResourceStub.args[1][2].should.equal(Application); + }); + + it('should pass the callback to dataStore#getResource', function() { + getResourceStub.args[0][3].should.equal(callback); + getResourceStub.args[1][3].should.equal(callback); + }); + }); + + describe('#getSigningApiKey(options, callback)', function() { + var callback; + var getResourceStub; + var sandbox; + var dataStore; + var webConfig; + + before(function() { + dataStore = new DataStore({client: {apiKey: {id: 1, secret: 2}}}); + webConfig = new WebConfig(webConfigData, dataStore); + sandbox = sinon.sandbox.create(); + getResourceStub = sinon.stub(dataStore, 'getResource'); + callback = sinon.spy(); + webConfig.getSigningApiKey(callback); + webConfig.getSigningApiKey(opts, callback); + }); + + after(function() { + sandbox.restore(); + }); + + it('should call dataStore#getResource', function() { + /*jshint -W030 */ + getResourceStub.should.have.been.calledTwice; + /*jshint +W030 */ + }); + + it('should pass the correct href to dataStore#getResource', function() { + getResourceStub.args[0][0].should.equal(webConfigData.signingApiKey.href); + getResourceStub.args[1][0].should.equal(webConfigData.signingApiKey.href); + }); + + it('should pass expansion options, if passed, to dataStore#getResource', function() { + assert.isNotOk(getResourceStub.args[0][1]); + getResourceStub.args[1][1].should.equal(opts); + }); + + it('should pass the constructor for ApiKey to dataStore#getResource', function() { + getResourceStub.args[0][2].should.equal(ApiKey); + getResourceStub.args[1][2].should.equal(ApiKey); + }); + + it('should pass the callback to dataStore#getResource', function() { + getResourceStub.args[0][3].should.equal(callback); + getResourceStub.args[1][3].should.equal(callback); + }); + }); + + describe('#getTenant(options, callback)', function() { + var callback; + var getResourceStub; + var sandbox; + var dataStore; + var webConfig; + + before(function() { + dataStore = new DataStore({client: {apiKey: {id: 1, secret: 2}}}); + webConfig = new WebConfig(webConfigData, dataStore); + sandbox = sinon.sandbox.create(); + getResourceStub = sinon.stub(dataStore, 'getResource'); + callback = sinon.spy(); + webConfig.getTenant(callback); + webConfig.getTenant(opts, callback); + }); + + after(function() { + sandbox.restore(); + }); + + it('should call dataStore#getResource', function() { + /*jshint -W030 */ + getResourceStub.should.have.been.calledTwice; + /*jshint +W030 */ + }); + + it('should pass the correct href to dataStore#getResource', function() { + getResourceStub.args[0][0].should.equal(webConfigData.tenant.href); + getResourceStub.args[1][0].should.equal(webConfigData.tenant.href); + }); + + it('should pass expansion options, if passed, to dataStore#getResource', function() { + assert.isNotOk(getResourceStub.args[0][1]); + getResourceStub.args[1][1].should.equal(opts); + }); + + it('should pass the constructor for Tenant to dataStore#getResource', function() { + getResourceStub.args[0][2].should.equal(Tenant); + getResourceStub.args[1][2].should.equal(Tenant); + }); + + it('should pass the callback to dataStore#getResource', function() { + getResourceStub.args[0][3].should.equal(callback); + getResourceStub.args[1][3].should.equal(callback); + }); + }); +});