Permalink
Browse files

set clientId on remote actions for duplicate vote prevention

  • Loading branch information...
teropa committed Sep 6, 2015
1 parent 84c51e7 commit 59a8b529d7a712acf33a4c8deabc7948acb6cd38
Showing with 42 additions and 3 deletions.
  1. +3 −1 package.json
  2. +7 −0 src/action_creators.js
  3. +10 −0 src/client_id.js
  4. +3 −1 src/index.jsx
  5. +2 −0 src/reducer.js
  6. +4 −1 src/remote_action_middleware.js
  7. +13 −0 test/reducer_spec.js
@@ -25,10 +25,12 @@
"dependencies": {
"classnames": "^2.1.3",
"immutable": "^3.7.5",
"object-assign": "^4.0.1",
"react": "^0.13.3",
"react-redux": "^2.1.0",
"react-router": "^0.13.3",
"redux": "^2.0.0",
"socket.io-client": "^1.3.6"
"socket.io-client": "^1.3.6",
"uuid": "^2.0.1"
}
}
@@ -1,3 +1,10 @@
export function setClientId(clientId) {
return {
type: 'SET_CLIENT_ID',
clientId
};
}
export function setState(state) {
return {
type: 'SET_STATE',
@@ -0,0 +1,10 @@
import uuid from 'uuid';
export default function getClientId() {
let id = localStorage.getItem('clientId');
if (!id) {
id = uuid.v4();
localStorage.setItem('clientId', id);
}
return id;
}
@@ -4,8 +4,9 @@ import {createStore, applyMiddleware} from 'redux';
import {Provider} from 'react-redux';
import io from 'socket.io-client';
import reducer from './reducer';
import {setState} from './action_creators';
import {setClientId, setState} from './action_creators';
import remoteActionMiddleware from './remote_action_middleware';
import getClientId from './client_id';
import App from './components/App';
import {VotingContainer} from './components/Voting';
import {ResultsContainer} from './components/Results';
@@ -21,6 +22,7 @@ const createStoreWithMiddleware = applyMiddleware(
remoteActionMiddleware(socket)
)(createStore);
const store = createStoreWithMiddleware(reducer);
store.dispatch(setClientId(getClientId()));
const routes = <Route handler={App}>
<Route path="/results" handler={ResultsContainer} />
@@ -29,6 +29,8 @@ function resetVote(state) {
export default function(state = Map(), action) {
switch (action.type) {
case 'SET_CLIENT_ID':
return state.set('clientId', action.clientId);
case 'SET_STATE':
return resetVote(setState(state, action.state));
case 'VOTE':
@@ -1,6 +1,9 @@
import objectAssign from 'object-assign';
export default socket => store => next => action => {
if (action.meta && action.meta.remote) {
socket.emit('action', action);
const clientId = store.getState().get('clientId');
socket.emit('action', objectAssign({}, action, {clientId}));
}
return next(action);
}
@@ -5,6 +5,19 @@ import reducer from '../src/reducer';
describe('reducer', () => {
it('handles SET_CLIENT_ID', () => {
const initialState = Map();
const action = {
type: 'SET_CLIENT_ID',
clientId: '1234'
};
const nextState = reducer(initialState, action);
expect(nextState).to.equal(fromJS({
clientId: '1234'
}));
});
it('handles SET_STATE', () => {
const initialState = Map();
const action = {

1 comment on commit 59a8b52

@andiwinata

This comment has been minimized.

andiwinata commented on 59a8b52 Feb 5, 2017

Hey, is it necessary to put client ID inside redux store?
isn't that will always be the same for each client regardless any state?

Please sign in to comment.