Skip to content

Commit 3371786

Browse files
committed
duplicate vote prevention
1 parent 80b1cd6 commit 3371786

File tree

4 files changed

+68
-15
lines changed

4 files changed

+68
-15
lines changed

src/core.js

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,29 @@ export function next(state) {
3434
}
3535
}
3636

37-
export function vote(voteState, entry) {
37+
function removePreviousVote(voteState, voter) {
38+
const previousVote = voteState.getIn(['votes', voter]);
39+
if (previousVote) {
40+
return voteState.updateIn(['tally', previousVote], t => t - 1)
41+
.removeIn(['votes', voter]);
42+
} else {
43+
return voteState;
44+
}
45+
}
46+
47+
function addVote(voteState, entry, voter) {
3848
if (voteState.get('pair').includes(entry)) {
39-
return voteState.updateIn(
40-
['tally', entry],
41-
0,
42-
tally => tally + 1
43-
);
49+
return voteState.updateIn(['tally', entry], 0, t => t + 1)
50+
.setIn(['votes', voter], entry);
4451
} else {
4552
return voteState;
4653
}
4754
}
55+
56+
export function vote(voteState, entry, voter) {
57+
return addVote(
58+
removePreviousVote(voteState, voter),
59+
entry,
60+
voter
61+
);
62+
}

src/reducer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export default function reducer(state = INITIAL_STATE, action) {
88
return next(state);
99
case 'VOTE':
1010
return state.update('vote',
11-
voteState => vote(voteState, action.entry));
11+
voteState => vote(voteState, action.entry, action.clientId));
1212
}
1313
return state;
1414
}

test/core_spec.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,16 @@ describe('application logic', () => {
120120
vote(Map({
121121
round: 1,
122122
pair: List.of('Trainspotting', '28 Days Later')
123-
}), 'Trainspotting')
123+
}), 'Trainspotting', 'voter1')
124124
).to.equal(
125125
Map({
126126
round: 1,
127127
pair: List.of('Trainspotting', '28 Days Later'),
128128
tally: Map({
129129
'Trainspotting': 1
130+
}),
131+
votes: Map({
132+
voter1: 'Trainspotting'
130133
})
131134
})
132135
);
@@ -140,15 +143,47 @@ describe('application logic', () => {
140143
tally: Map({
141144
'Trainspotting': 3,
142145
'28 Days Later': 2
143-
})
144-
}), 'Trainspotting')
146+
}),
147+
votes: Map()
148+
}), 'Trainspotting', 'voter1')
145149
).to.equal(
146150
Map({
147151
round: 1,
148152
pair: List.of('Trainspotting', '28 Days Later'),
149153
tally: Map({
150154
'Trainspotting': 4,
151155
'28 Days Later': 2
156+
}),
157+
votes: Map({
158+
voter1: 'Trainspotting'
159+
})
160+
})
161+
);
162+
});
163+
164+
it('nullifies previous vote for the same voter', () => {
165+
expect(
166+
vote(Map({
167+
round: 1,
168+
pair: List.of('Trainspotting', '28 Days Later'),
169+
tally: Map({
170+
'Trainspotting': 3,
171+
'28 Days Later': 2
172+
}),
173+
votes: Map({
174+
voter1: '28 Days Later'
175+
})
176+
}), 'Trainspotting', 'voter1')
177+
).to.equal(
178+
Map({
179+
round: 1,
180+
pair: List.of('Trainspotting', '28 Days Later'),
181+
tally: Map({
182+
'Trainspotting': 4,
183+
'28 Days Later': 1
184+
}),
185+
votes: Map({
186+
voter1: 'Trainspotting'
152187
})
153188
})
154189
);

test/reducer_spec.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,17 @@ describe('reducer', () => {
3939
},
4040
entries: []
4141
});
42-
const action = {type: 'VOTE', entry: 'Trainspotting'};
42+
const action = {type: 'VOTE', entry: 'Trainspotting', clientId: 'voter1'};
4343
const nextState = reducer(initialState, action);
4444

4545
expect(nextState).to.equal(fromJS({
4646
vote: {
4747
round: 1,
4848
pair: ['Trainspotting', '28 Days Later'],
49-
tally: {Trainspotting: 1}
49+
tally: {Trainspotting: 1},
50+
votes: {
51+
voter1: 'Trainspotting'
52+
}
5053
},
5154
entries: []
5255
}));
@@ -64,9 +67,9 @@ describe('reducer', () => {
6467
const actions = [
6568
{type: 'SET_ENTRIES', entries: ['Trainspotting', '28 Days Later']},
6669
{type: 'NEXT'},
67-
{type: 'VOTE', entry: 'Trainspotting'},
68-
{type: 'VOTE', entry: '28 Days Later'},
69-
{type: 'VOTE', entry: 'Trainspotting'},
70+
{type: 'VOTE', entry: 'Trainspotting', clientId: 'voter1'},
71+
{type: 'VOTE', entry: '28 Days Later', clientId: 'voter2'},
72+
{type: 'VOTE', entry: 'Trainspotting', clientId: 'voter3'},
7073
{type: 'NEXT'}
7174
];
7275
const finalState = actions.reduce(reducer, Map());

0 commit comments

Comments
 (0)