Unverified Commit 70749111 authored by Kyle Keating's avatar Kyle Keating Committed by GitHub

Merge pull request #1493 from hypothesis/rpc-server-actions

Add changeFocusModeUser action
parents e9400300 6551b4b5
'use strict'; 'use strict';
/**
* Return the mapped methods that can be called remotely via this server.
*
* @param {Object} store - The global store
* @return {Object}
*/
const registeredMethods = store => {
return {
changeFocusModeUser: store.changeFocusModeUser,
};
};
/** /**
* Begin responding to JSON-RPC requests from frames on other origins. * Begin responding to JSON-RPC requests from frames on other origins.
* *
...@@ -15,13 +28,14 @@ ...@@ -15,13 +28,14 @@
* http://www.jsonrpc.org/specification * http://www.jsonrpc.org/specification
* *
* The only part that we support so far is receiving JSON-RPC 2.0 requests (not * The only part that we support so far is receiving JSON-RPC 2.0 requests (not
* notifications) without any parameters and sending back a successful * notifications) and sending back a successful "ok" response.
* response. Notifications (JSON-RPC calls that don't require a response),
* method parameters, and error responses are not yet supported.
* *
* All methods called upon must be mapped in the `registeredMethods` function.
*/ */
// @ngInject // @ngInject
function start(store, settings, $window) { function start(store, settings, $window) {
const methods = registeredMethods(store);
$window.addEventListener('message', function receiveMessage(event) { $window.addEventListener('message', function receiveMessage(event) {
let allowedOrigins = settings.rpcAllowedOrigins || []; let allowedOrigins = settings.rpcAllowedOrigins || [];
...@@ -38,28 +52,25 @@ function start(store, settings, $window) { ...@@ -38,28 +52,25 @@ function start(store, settings, $window) {
/** Return a JSON-RPC response to the given JSON-RPC request object. */ /** Return a JSON-RPC response to the given JSON-RPC request object. */
function jsonRpcResponse(request) { function jsonRpcResponse(request) {
// The set of methods that clients can call. const method = methods[request.method];
let methods = {
searchUris: store.searchUris,
};
let method = methods[request.method];
let response = { // Return an error response if the method name is not registered with
// registeredMethods.
if (method === undefined) {
return {
jsonrpc: '2.0', jsonrpc: '2.0',
id: request.id, id: request.id,
error: { code: -32601, message: 'Method not found' },
}; };
}
if (method) { // Call the method and return the result response.
response.result = method(); if (request.params) {
method(...request.params);
} else { } else {
response.error = { method();
code: -32601,
message: 'Method not found',
};
} }
return { jsonrpc: '2.0', result: 'ok', id: request.id };
return response;
} }
} }
......
...@@ -8,6 +8,12 @@ ...@@ -8,6 +8,12 @@
* - The current filter query * - The current filter query
*/ */
/**
* @typedef User
* @property {string} username - Unique user's username
* @property {string} displayName - User's display name
*/
'use strict'; 'use strict';
const { createSelector } = require('reselect'); const { createSelector } = require('reselect');
...@@ -114,7 +120,7 @@ function init(settings) { ...@@ -114,7 +120,7 @@ function init(settings) {
selectedTab: TAB_DEFAULT, selectedTab: TAB_DEFAULT,
focusMode: { focusMode: {
enabled: settings.hasOwnProperty('focus'), // readonly enabled: settings.hasOwnProperty('focus'),
focused: true, focused: true,
// Copy over the focus confg from settings object // Copy over the focus confg from settings object
config: { ...(settings.focus ? settings.focus : {}) }, config: { ...(settings.focus ? settings.focus : {}) },
...@@ -162,6 +168,19 @@ const update = { ...@@ -162,6 +168,19 @@ const update = {
}; };
}, },
CHANGE_FOCUS_MODE_USER: function(state, action) {
return {
focusMode: {
...state.focusMode,
enabled: true,
focused: true,
config: {
user: { ...action.user },
},
},
};
},
SET_FORCE_VISIBLE: function(state, action) { SET_FORCE_VISIBLE: function(state, action) {
return { forceVisible: action.forceVisible }; return { forceVisible: action.forceVisible };
}, },
...@@ -344,6 +363,18 @@ function setFocusModeFocused(focused) { ...@@ -344,6 +363,18 @@ function setFocusModeFocused(focused) {
}; };
} }
/**
* Changes the focused user and sets focused enabled to `true`.
*
* @param {User} user - The user to focus on
*/
function changeFocusModeUser(user) {
return {
type: actions.CHANGE_FOCUS_MODE_USER,
user,
};
}
/** Sets the sort key for the annotation list. */ /** Sets the sort key for the annotation list. */
function setSortKey(key) { function setSortKey(key) {
return { return {
...@@ -469,6 +500,7 @@ module.exports = { ...@@ -469,6 +500,7 @@ module.exports = {
setCollapsed: setCollapsed, setCollapsed: setCollapsed,
setFilterQuery: setFilterQuery, setFilterQuery: setFilterQuery,
setFocusModeFocused: setFocusModeFocused, setFocusModeFocused: setFocusModeFocused,
changeFocusModeUser: changeFocusModeUser,
setForceVisible: setForceVisible, setForceVisible: setForceVisible,
setSortKey: setSortKey, setSortKey: setSortKey,
toggleSelectedAnnotations: toggleSelectedAnnotations, toggleSelectedAnnotations: toggleSelectedAnnotations,
......
...@@ -201,6 +201,20 @@ describe('sidebar/store/modules/selection', () => { ...@@ -201,6 +201,20 @@ describe('sidebar/store/modules/selection', () => {
}); });
}); });
describe('changeFocusModeUser()', function() {
it('sets the focused user and enables focus mode', function() {
store.setFocusModeFocused(false);
store.changeFocusModeUser({
username: 'testuser',
displayName: 'Test User',
});
assert.equal(store.focusModeUsername(), 'testuser');
assert.equal(store.focusModeUserPrettyName(), 'Test User');
assert.equal(store.focusModeFocused(), true);
assert.equal(store.focusModeEnabled(), true);
});
});
describe('setFocusModeFocused()', function() { describe('setFocusModeFocused()', function() {
it('sets the focus mode to enabled', function() { it('sets the focus mode to enabled', function() {
store.setFocusModeFocused(true); store.setFocusModeFocused(true);
......
...@@ -12,7 +12,7 @@ describe('crossOriginRPC', function() { ...@@ -12,7 +12,7 @@ describe('crossOriginRPC', function() {
beforeEach(function() { beforeEach(function() {
fakeStore = { fakeStore = {
searchUris: sinon.stub().returns('THE_SEARCH_URIS'), changeFocusModeUser: sinon.stub(),
}; };
fakeWindow = { fakeWindow = {
...@@ -46,28 +46,74 @@ describe('crossOriginRPC', function() { ...@@ -46,28 +46,74 @@ describe('crossOriginRPC', function() {
assert.isTrue(fakeWindow.addEventListener.calledWith('message')); assert.isTrue(fakeWindow.addEventListener.calledWith('message'));
}); });
it('sends a response with the result from the called method', function() { it('sends a response with the "ok" result', function() {
crossOriginRPC.server.start(fakeStore, settings, fakeWindow); crossOriginRPC.server.start(fakeStore, settings, fakeWindow);
postMessage({ postMessage({
data: { method: 'searchUris', id: 42 }, data: { method: 'changeFocusModeUser', id: 42 },
origin: 'https://allowed1.com', origin: 'https://allowed1.com',
source: source, source: source,
}); });
assert.isTrue(source.postMessage.calledOnce); assert.isTrue(source.postMessage.calledOnce);
assert.isTrue( assert.isTrue(
source.postMessage.calledWithExactly( source.postMessage.calledWithExactly(
{ {
jsonrpc: '2.0', jsonrpc: '2.0',
id: 42, id: 42,
result: 'THE_SEARCH_URIS', result: 'ok',
}, },
'https://allowed1.com' 'https://allowed1.com'
) )
); );
}); });
it('calls the registered method with the provided params', function() {
crossOriginRPC.server.start(fakeStore, settings, fakeWindow);
postMessage({
data: {
method: 'changeFocusModeUser',
id: 42,
params: ['one', 'two'],
},
origin: 'https://allowed1.com',
source: source,
});
assert.isTrue(
fakeStore.changeFocusModeUser.calledWithExactly('one', 'two')
);
});
it('calls the registered method with no params', function() {
crossOriginRPC.server.start(fakeStore, settings, fakeWindow);
postMessage({
data: {
method: 'changeFocusModeUser',
id: 42,
},
origin: 'https://allowed1.com',
source: source,
});
assert.isTrue(fakeStore.changeFocusModeUser.calledWithExactly());
});
it('does not call the unregistered method', function() {
crossOriginRPC.server.start(fakeStore, settings, fakeWindow);
postMessage({
data: {
method: 'unregisteredMethod',
id: 42,
},
origin: 'https://allowed1.com',
source: source,
});
assert.isTrue(fakeStore.changeFocusModeUser.notCalled);
});
[ [
{}, {},
{ rpcAllowedOrigins: [] }, { rpcAllowedOrigins: [] },
...@@ -78,7 +124,7 @@ describe('crossOriginRPC', function() { ...@@ -78,7 +124,7 @@ describe('crossOriginRPC', function() {
postMessage({ postMessage({
origin: 'https://notallowed.com', origin: 'https://notallowed.com',
data: { method: 'searchUris', id: 42 }, data: { method: 'changeFocusModeUser', id: 42 },
source: source, source: source,
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment