Skip to content

Commit b1048e0

Browse files
authored
Merge pull request #143 from dedis/front-fix-result
Fix ballot encoding, and the results page
2 parents 8625e45 + cb8fedc commit b1048e0

File tree

8 files changed

+120
-29
lines changed

8 files changed

+120
-29
lines changed

docs/ballot_encoding.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ The answers to questions are encoded in the following way, with one question per
1313
1414
TYPE = "select"|"text"|"rank"
1515
SEP = ":"
16-
ID = up to 3 bytes, encoded in base64
16+
ID = 3 bytes, encoded in base64
1717
ANSWERS = <answer>[","<answer>]*
1818
ANSWER = <select_answer>|<text_answer>|<rank_answer>
1919
SELECT_ANSWER = "0"|"1"

web/frontend/src/mocks/handlers.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const CHANGE_STATUS_TIMER = 2000;
4141
const INIT_TIMER = 1000;
4242
const SETUP_TIMER = 2000;
4343
const SHUFFLE_TIMER = 2000;
44-
const DECRYPT_TIMER = 3000;
44+
const DECRYPT_TIMER = 1000;
4545

4646
const defaultProxy = 'http://localhost/';
4747

@@ -140,8 +140,8 @@ export const handlers = [
140140
Result: [],
141141
Roster: mockRoster,
142142
Configuration: configuration,
143-
BallotSize: 290,
144-
ChunksPerBallot: 10,
143+
BallotSize: 291,
144+
ChunksPerBallot: 11,
145145
});
146146

147147
return newElectionID;

web/frontend/src/mocks/mockData.ts

+56
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,31 @@ const mockElection2: any = {
175175
],
176176
};
177177

178+
const mockElection3: any = {
179+
MainTitle: 'Lunch',
180+
Scaffold: [
181+
{
182+
ID: '3cVHIxpx',
183+
Title: 'Choose your lunch',
184+
Order: ['PGP'],
185+
Ranks: [],
186+
Selects: [],
187+
Texts: [
188+
{
189+
ID: 'PGP',
190+
Title: 'Select what you want',
191+
MaxN: 4,
192+
MinN: 0,
193+
MaxLength: 50,
194+
Regex: '',
195+
Choices: ['Firstname', 'Main 🍕', 'Drink 🧃', 'Dessert 🍰'],
196+
},
197+
],
198+
Subjects: [],
199+
},
200+
],
201+
};
202+
178203
const mockElectionResult21: Results = {
179204
SelectResultIDs: [(0x3fb2).toString(), (0xa319).toString()],
180205
SelectResult: [
@@ -220,14 +245,45 @@ const mockElectionResult23: Results = {
220245
TextResult: [['Another Name', 'Jane Doe']],
221246
};
222247

248+
const mockElectionResult31: Results = {
249+
SelectResultIDs: [],
250+
SelectResult: [],
251+
RankResultIDs: [],
252+
RankResult: [],
253+
TextResultIDs: ['PGP'],
254+
TextResult: [['Alice', 'Pizza', 'Ice cold water', '🍒🍒🍒🍒']],
255+
};
256+
257+
const mockElectionResult32: Results = {
258+
SelectResultIDs: [],
259+
SelectResult: [],
260+
RankResultIDs: [],
261+
RankResult: [],
262+
TextResultIDs: ['PGP'],
263+
TextResult: [['Bob', 'Pizza', 'Coke', '🍒🍒🍒']],
264+
};
265+
266+
const mockElectionResult33: Results = {
267+
SelectResultIDs: null,
268+
SelectResult: null,
269+
RankResultIDs: null,
270+
RankResult: null,
271+
TextResultIDs: null,
272+
TextResult: null,
273+
};
274+
223275
export {
224276
mockElection1,
225277
mockElectionResult11,
226278
mockElectionResult12,
227279
mockElection2,
228280
mockElectionResult21,
229281
mockElectionResult22,
282+
mockElection3,
230283
mockElectionResult23,
284+
mockElectionResult31,
285+
mockElectionResult32,
286+
mockElectionResult33,
231287
mockRoster,
232288
mockNodes,
233289
};

web/frontend/src/mocks/setupMockElections.ts

+19
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@ import { NodeStatus } from 'types/node';
55
import {
66
mockElection1,
77
mockElection2,
8+
mockElection3,
89
mockElectionResult11,
910
mockElectionResult12,
1011
mockElectionResult21,
1112
mockElectionResult22,
1213
mockElectionResult23,
14+
mockElectionResult31,
15+
mockElectionResult32,
16+
mockElectionResult33,
1317
mockNodes,
1418
mockRoster,
1519
} from './mockData';
@@ -39,6 +43,7 @@ const setupMockElection = () => {
3943

4044
const electionID1 = '36kSJ0tH';
4145
const electionID2 = 'Bnq9gLmf';
46+
const electionID3 = 'Afdv4ffl';
4247

4348
mockElections.set(electionID1, {
4449
ElectionID: electionID1,
@@ -69,6 +74,20 @@ const setupMockElection = () => {
6974
mockResults.set(electionID2, [mockElectionResult21, mockElectionResult22, mockElectionResult23]);
7075
mockDKG.set(electionID2, mockDKGSetup);
7176

77+
mockElections.set(electionID3, {
78+
ElectionID: electionID3,
79+
Status: Status.Open,
80+
Pubkey: 'XL4V6EMIICW',
81+
Result: [],
82+
Roster: mockRoster,
83+
Configuration: unmarshalConfig(mockElection3),
84+
BallotSize: 291,
85+
ChunksPerBallot: 11,
86+
});
87+
88+
mockResults.set(electionID3, [mockElectionResult31, mockElectionResult32, mockElectionResult33]);
89+
mockDKG.set(electionID3, mockDKGSetup);
90+
7291
return { mockElections, mockResults, mockDKG, mockNodeProxyAddresses };
7392
};
7493

web/frontend/src/pages/ballot/Show.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const Ballot: FC = () => {
2727

2828
const { electionId } = useParams();
2929
const UserID = sessionStorage.getItem('id');
30-
const { loading, configObj, electionID, status, pubKey, ballotSize, chunksPerBallot } =
30+
const { loading, configObj, electionID, status, pubKey, chunksPerBallot } =
3131
useElection(electionId);
3232
const { configuration, answers, setAnswers } = useConfiguration(configObj);
3333

web/frontend/src/pages/ballot/components/VoteEncode.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ export function voteEncode(answers: Answers, chunksPerBallot: number): string[]
77
let encodedBallot = '';
88

99
answers.SelectAnswers.forEach((selectAnswer, id) => {
10-
encodedBallot += SELECT + ':' + id + ':';
10+
encodedBallot += SELECT + ':' + Buffer.from(id).toString('base64') + ':';
1111
selectAnswer.forEach((answer) => (encodedBallot += answer ? '1,' : '0,'));
1212
encodedBallot = encodedBallot.slice(0, -1);
1313
encodedBallot += '\n';
1414
});
1515

1616
answers.RankAnswers.forEach((rankAnswer, id) => {
17-
encodedBallot += RANK + ':' + id + ':';
17+
encodedBallot += RANK + ':' + Buffer.from(id).toString('base64') + ':';
1818
const position = Array<number>(rankAnswer.length);
1919
for (let i = 0; i < rankAnswer.length; i++) {
2020
position[rankAnswer[i]] = i;
@@ -25,7 +25,7 @@ export function voteEncode(answers: Answers, chunksPerBallot: number): string[]
2525
});
2626

2727
answers.TextAnswers.forEach((textAnswer, id) => {
28-
encodedBallot += TEXT + ':' + id + ':';
28+
encodedBallot += TEXT + ':' + Buffer.from(id).toString('base64') + ':';
2929
// each answer is first transformed into bytes then encoded in base64
3030
textAnswer.forEach((answer) => (encodedBallot += Buffer.from(answer).toString('base64') + ','));
3131
encodedBallot = encodedBallot.slice(0, -1);

web/frontend/src/pages/election/Result.tsx

+36-20
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,15 @@ const ElectionResult: FC = () => {
7575
let textRes: TextResults = new Map<ID, string[][]>();
7676

7777
result.forEach((res) => {
78-
groupByID(selectRes, res.SelectResultIDs, res.SelectResult, true);
79-
groupByID(rankRes, res.RankResultIDs, res.RankResult);
80-
groupByID(textRes, res.TextResultIDs, res.TextResult);
78+
if (
79+
res.SelectResultIDs !== null &&
80+
res.RankResultIDs !== null &&
81+
res.TextResultIDs !== null
82+
) {
83+
groupByID(selectRes, res.SelectResultIDs, res.SelectResult, true);
84+
groupByID(rankRes, res.RankResultIDs, res.RankResult);
85+
groupByID(textRes, res.TextResultIDs, res.TextResult);
86+
}
8187
});
8288

8389
return { rankRes, selectRes, textRes };
@@ -104,31 +110,39 @@ const ElectionResult: FC = () => {
104110
switch (element.Type) {
105111
case RANK:
106112
const rank = element as RankQuestion;
107-
res = countRankResult(rankResult.get(id), element as RankQuestion).resultsInPercent.map(
108-
(percent, index) => {
109-
return { Candidate: rank.Choices[index], Percentage: `${percent}%` };
110-
}
111-
);
112-
dataToDownload.push({ Title: element.Title, Results: res });
113+
114+
if (rankResult.has(id)) {
115+
res = countRankResult(rankResult.get(id), element as RankQuestion).resultsInPercent.map(
116+
(percent, index) => {
117+
return { Candidate: rank.Choices[index], Percentage: `${percent}%` };
118+
}
119+
);
120+
dataToDownload.push({ Title: element.Title, Results: res });
121+
}
113122
break;
114123

115124
case SELECT:
116125
const select = element as SelectQuestion;
117-
res = countSelectResult(selectResult.get(id)).resultsInPercent.map((percent, index) => {
118-
return { Candidate: select.Choices[index], Percentage: `${percent}%` };
119-
});
120-
dataToDownload.push({ Title: element.Title, Results: res });
126+
127+
if (selectResult.has(id)) {
128+
res = countSelectResult(selectResult.get(id)).resultsInPercent.map((percent, index) => {
129+
return { Candidate: select.Choices[index], Percentage: `${percent}%` };
130+
});
131+
dataToDownload.push({ Title: element.Title, Results: res });
132+
}
121133
break;
122134

123135
case SUBJECT:
124136
getResultData(element as Subject, dataToDownload);
125137
break;
126138

127139
case TEXT:
128-
res = Array.from(countTextResult(textResult.get(id)).resultsInPercent).map((r) => {
129-
return { Candidate: r[0], Percentage: `${r[1]}%` };
130-
});
131-
dataToDownload.push({ Title: element.Title, Results: res });
140+
if (textResult.has(id)) {
141+
res = Array.from(countTextResult(textResult.get(id)).resultsInPercent).map((r) => {
142+
return { Candidate: r[0], Percentage: `${r[1]}%` };
143+
});
144+
dataToDownload.push({ Title: element.Title, Results: res });
145+
}
132146
break;
133147
}
134148
});
@@ -160,16 +174,18 @@ const ElectionResult: FC = () => {
160174
return (
161175
<div className="pl-4 pb-4 sm:pl-6 sm:pb-6">
162176
<h2 className="text-lg pb-2">{element.Title}</h2>
163-
{element.Type === RANK && (
177+
{element.Type === RANK && rankResult.has(element.ID) && (
164178
<RankResult rank={element as RankQuestion} rankResult={rankResult.get(element.ID)} />
165179
)}
166-
{element.Type === SELECT && (
180+
{element.Type === SELECT && selectResult.has(element.ID) && (
167181
<SelectResult
168182
select={element as SelectQuestion}
169183
selectResult={selectResult.get(element.ID)}
170184
/>
171185
)}
172-
{element.Type === TEXT && <TextResult textResult={textResult.get(element.ID)} />}
186+
{element.Type === TEXT && textResult.has(element.ID) && (
187+
<TextResult textResult={textResult.get(element.ID)} />
188+
)}
173189
</div>
174190
);
175191
};

web/frontend/src/types/getObjectType.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import ShortUniqueId from 'short-unique-id';
22
import * as types from './configuration';
33
import { ID, RANK, SELECT, SUBJECT, TEXT } from './configuration';
44

5-
const uid: Function = new ShortUniqueId({ length: 8 });
5+
const uid: Function = new ShortUniqueId({ length: 3 });
66

77
const emptyConfiguration = (): types.Configuration => {
88
return { MainTitle: '', Scaffold: [] };

0 commit comments

Comments
 (0)