Files: c46ad9c39623cd98b6cbb308d0c0870f15ff701c / results / sync / buildResults.js
2618 bytesRaw
1 | const getContent = require('ssb-msg-content') |
2 | const { isChooseOnePoll, isPosition } = require('ssb-poll-schema') |
3 | const PositionChoiceError = require('../../errors/sync/positionChoiceError') |
4 | const PositionLateError = require('../../errors/sync/positionLateError') |
5 | const PositionTypeError = require('../../errors/sync/positionTypeError') |
6 | |
7 | // Expects `poll` and `position` objects passed in to be of shape: |
8 | // { |
9 | // key, |
10 | // value: { |
11 | // content: {...}, |
12 | // timestamp: ... |
13 | // author: ... |
14 | // } |
15 | // } |
16 | // |
17 | // postions must be of the correct type ie: type checked by the caller. |
18 | |
19 | // TODO find a better home for this (it is not strongly in poll nor position domain) |
20 | module.exports = function ({positions, poll}) { |
21 | if (isChooseOnePoll(poll)) { |
22 | return chooseOneResults({positions, poll}) |
23 | } |
24 | } |
25 | |
26 | function chooseOneResults ({positions, poll}) { |
27 | var results = getContent(poll) |
28 | .details |
29 | .choices |
30 | .map(choice => { |
31 | return { |
32 | choice, |
33 | voters: {} |
34 | } |
35 | }) |
36 | |
37 | return positions.reduce(function (acc, position) { |
38 | const { author } = position.value |
39 | const { choice } = getContent(position).details |
40 | |
41 | if (isInvalidType({position, poll})) { |
42 | console.log('got an aninvalid position type') |
43 | acc.errors.push(PositionTypeError({position})) |
44 | return acc |
45 | } |
46 | |
47 | if (isInvalidChoice({position, poll})) { |
48 | acc.errors.push(PositionChoiceError({position})) |
49 | return acc |
50 | } |
51 | |
52 | if (isPositionLate({position, poll})) { |
53 | acc.errors.push(PositionLateError({position})) |
54 | return acc |
55 | } |
56 | |
57 | deleteExistingVotesByAuthor({results: acc.results, author}) |
58 | acc.results[choice].voters[author] = position |
59 | |
60 | return acc |
61 | }, {errors: [], results}) |
62 | } |
63 | |
64 | // !!! assumes these are already sorted by time. |
65 | // modifies results passed in |
66 | function deleteExistingVotesByAuthor ({author, results}) { |
67 | results.forEach(result => { |
68 | if (result.voters[author]) { |
69 | delete result.voters[author] |
70 | } |
71 | }) |
72 | } |
73 | |
74 | function isInvalidType ({position, poll}) { |
75 | // TODO:this is super fragile. We should be using a parsed or decorated poll |
76 | const pollType = poll.value.content.details.type |
77 | return !isPosition[pollType](position) |
78 | } |
79 | |
80 | function isInvalidChoice ({position, poll}) { |
81 | const { choice } = position.value.content.details |
82 | // TODO:this is super fragile. We should be using a parsed or decorated poll |
83 | return choice >= poll.value.content.details.choices.length |
84 | } |
85 | |
86 | function isPositionLate ({position, poll}) { |
87 | // TODO:this is super fragile. We should be using a parsed or decorated poll |
88 | return position.value.timestamp > poll.value.content.closesAt |
89 | } |
90 |
Built with git-ssb-web