From fbda1c403380275fc965045efeaa2a0446fdf4a3 Mon Sep 17 00:00:00 2001 From: Jeff Cuevas-Koch <4649003+cuevaskoch@users.noreply.github.com> Date: Tue, 20 Aug 2019 10:00:38 -0700 Subject: [PATCH] feat(voip): Add user filters for call state. (#62) Allows API consumers to retrieve notifications of updated call state restricted by a set of vehicles, users, or both. Restrictions are independent of one another, so specifying a users filter still returns all vehicles and vice versa. Feature added to support VOIP scenarios where the same user is accessing VOIP features from different browser windows or computers. Signed-off-by: Jeff Cuevas-Koch --- src/examples/subscribe_call_states.test.js | 18 ++++++++-- src/resources/CallStatesRealTimeContext.js | 25 ++++++++++++++ .../CallStatesRealTimeContext.test.js | 33 +++++++++++++++++-- 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/examples/subscribe_call_states.test.js b/src/examples/subscribe_call_states.test.js index e4436f2..e58f82b 100644 --- a/src/examples/subscribe_call_states.test.js +++ b/src/examples/subscribe_call_states.test.js @@ -22,7 +22,7 @@ describe('When subscribing to call states', () => { afterEach(fetchMock.restore); after(() => server.close()); - it('should get updated call states for a single vehicle', () => { + it('should get updated call states for a single vehicle and all users', () => { const vehicleHref = '1/SYNC/vehicles/123'; api.logIn({ username: 'charlie@example.com', password: 'securepassword' }); @@ -33,19 +33,31 @@ describe('When subscribing to call states', () => { .on('update', callState => callState); // do things with callState }); - it('should get updated call states for multiple vehicles', () => { + it('should get updated call states for multiple vehicles and a single user', () => { const vehicles = [ { href: '1/SYNC/vehicles/123' }, { href: '1/SYNC/vehicles/456' }, { href: '1/SYNC/vehicles/789' }, ]; - + const user = { href: '1/SYNC/users/1' }; api.logIn({ username: 'charlie@example.com', password: 'securepassword' }); return api.customer('SYNC') .realTime() .callStates() .forVehicles(vehicles) + .forUser(user) .on('update', callState => callState); // do things with callState }); + + it('should get updated call states for all vehicles and a single user', () => { + const user = { href: '1/SYNC/users/1' }; + + api.logIn({ username: 'charlie@example.com', password: 'securepassword' }); + return api.customer('SYNC') + .realTime() + .callStates() + .forUser(user) + .on('update', callState => callState); // do things with callState + }) }); diff --git a/src/resources/CallStatesRealTimeContext.js b/src/resources/CallStatesRealTimeContext.js index a930570..9d06a76 100644 --- a/src/resources/CallStatesRealTimeContext.js +++ b/src/resources/CallStatesRealTimeContext.js @@ -14,11 +14,13 @@ class CallStatesRealTimeContext extends RealTimeContext { super(realTimeClient, entityName, customerCode); this.filters = { vehicles: [], + users: [], }; } /** * Restrict subscriptions created by this context to a single vehicle. + * Vehicle restrictions are independent of user subscriptions. * @param {Resource|string} vehicle Href or resource representation of a Vehicle. * @returns {CallStatesRealTimeContext} Context with filter applied. */ @@ -28,6 +30,7 @@ class CallStatesRealTimeContext extends RealTimeContext { /** * Restrict subscriptions created by this context to a set of vehicles. + * Vehicle restrictions are independent of user subscriptions. * @param {Array.} vehicles Array of href or resource representations of * Vehicles. * @returns {CallStatesRealTimeContext} Context with filter applied. @@ -37,6 +40,28 @@ class CallStatesRealTimeContext extends RealTimeContext { this.filters.vehicles = vehicles.map(RealTimeContext.resolveHref); return this; } + + /** + * Restrict subscriptions created by this context to a single user. + * User restrictions are independent of vehicle subscriptions. + * @param {Resource|string} user Href or resource representation of a Vehicle. + * @returns {CallStatesRealTimeContext} Context with filter applied. + */ + forUser(user) { + return this.forUsers([user]); + } + + /** + * Restrict subscriptions created by this context to a set of users. + * User restrictions are independent of vehicle subscriptions. + * @param {Array.} users Array of href or resource representations of Users. + * @returns {CallStatesRealTimeContext} Context with filter applied. + */ + forUsers(users) { + this.assertSubscriptionNotStarted(); + this.filters.users = users.map(RealTimeContext.resolveHref); + return this; + } } export default CallStatesRealTimeContext; diff --git a/src/resources/CallStatesRealTimeContext.test.js b/src/resources/CallStatesRealTimeContext.test.js index f426a49..787074e 100644 --- a/src/resources/CallStatesRealTimeContext.test.js +++ b/src/resources/CallStatesRealTimeContext.test.js @@ -17,7 +17,7 @@ describe('When creating a subscription for Call States', () => { const subject = new CallStatesRealTimeContext(realTimeClient, customerCode); const vehicleHref = '123'; - const expectedFilters = { vehicles: [vehicleHref] }; + const expectedFilters = { vehicles: [vehicleHref], users: [] }; subject.forVehicle(vehicleHref).on('update', () => { }); const options = { closeConnection: true, realTimeClient }; @@ -31,7 +31,7 @@ describe('When creating a subscription for Call States', () => { const subject = new CallStatesRealTimeContext(realTimeClient, customerCode); const vehicleHrefs = ['123', '456', '489']; - const expectedFilters = { vehicles: vehicleHrefs }; + const expectedFilters = { vehicles: vehicleHrefs, users: [] }; subject.forVehicles(vehicleHrefs).on('update', () => { }); @@ -40,6 +40,35 @@ describe('When creating a subscription for Call States', () => { .should.eventually.become(expectedFilters); }); + it('can add filters for a single user', () => { + const server = mock.getServer(); + const realTimeClient = new RealTimeClient(mock.authenticatedClient, mock.options); + const subject = new CallStatesRealTimeContext(realTimeClient, customerCode); + + const userHref = '123'; + const expectedFilters = { users: [userHref], vehicles: [] }; + subject.forUser(userHref).on('update', () => { }); + + const options = { closeConnection: true, realTimeClient }; + return server.verifySubscription(entity, options) + .should.eventually.become(expectedFilters); + }); + + it('can add filters for multiple users', () => { + const server = mock.getServer(); + const realTimeClient = new RealTimeClient(mock.authenticatedClient, mock.options); + const subject = new CallStatesRealTimeContext(realTimeClient, customerCode); + + const userHrefs = ['123', '456', '489']; + const expectedFilters = { users: userHrefs, vehicles: [] }; + + subject.forUsers(userHrefs).on('update', () => { }); + + const options = { closeConnection: true, realTimeClient }; + return server.verifySubscription(entity, options) + .should.eventually.become(expectedFilters); + }); + it('should handle entity updates', () => { const server = mock.getServer(); const realTimeClient = new RealTimeClient(mock.authenticatedClient, mock.options);