Files: 499687916fec256f9f5439cc8479674da2ce180d / poll / async / get.js
3082 bytesRaw
1 | const pull = require('pull-stream') |
2 | const sort = require('ssb-sort') |
3 | const getContent = require('ssb-msg-content') |
4 | const { isPoll, isPosition, isChooseOnePoll, isChooseOnePosition } = require('ssb-poll-schema') |
5 | isPoll.chooseOne = isChooseOnePoll |
6 | isPosition.chooseOne = isChooseOnePosition |
7 | const buildResults = require('../../results/sync/buildResults') |
8 | const { CHOOSE_ONE, ERROR_POSITION_TYPE } = require('../../types') |
9 | const publishChooseOnePosition = require('../../position/async/buildChooseOne') |
10 | |
11 | module.exports = function (server) { |
12 | return function get (key, cb) { |
13 | server.get(key, (err, value) => { |
14 | if (err) return cb(err) |
15 | |
16 | var poll = { key, value } |
17 | if (!isPoll(poll)) return cb(new Error('scuttle-poll could not get poll, key provided was not a valid poll key')) |
18 | |
19 | pull( |
20 | createBacklinkStream(key), |
21 | pull.collect((err, msgs) => { |
22 | if (err) return cb(err) |
23 | |
24 | cb(null, decoratePoll(poll, msgs)) |
25 | }) |
26 | ) |
27 | }) |
28 | } |
29 | |
30 | function createBacklinkStream (key) { |
31 | var filterQuery = { |
32 | $filter: { |
33 | dest: key |
34 | } |
35 | } |
36 | |
37 | return server.backlinks.read({ |
38 | query: [filterQuery], |
39 | index: 'DTA' // use asserted timestamps |
40 | }) |
41 | } |
42 | } |
43 | |
44 | function decoratePoll (rawPoll, msgs = []) { |
45 | const { |
46 | author, |
47 | content: { |
48 | title, |
49 | body, |
50 | channel, |
51 | details: { type } |
52 | }, |
53 | recps, |
54 | mentions |
55 | } = rawPoll.value |
56 | |
57 | const poll = Object.assign({}, rawPoll, { |
58 | type, |
59 | author, |
60 | title, |
61 | body, |
62 | channel, |
63 | recps, |
64 | mentions, |
65 | |
66 | actions: { |
67 | publishPosition |
68 | }, |
69 | positions: [], |
70 | results: {}, |
71 | errors: [], |
72 | decorated: true |
73 | }) |
74 | |
75 | function publishPosition (opts, cb) { |
76 | if (poll.type === CHOOSE_ONE) { |
77 | publishChooseOnePosition({ |
78 | poll, |
79 | choice: opts.choice, |
80 | reason: opts.reason |
81 | }, cb) |
82 | } |
83 | } |
84 | |
85 | // TODO add missingContext warnings to each msg |
86 | msgs = sort(msgs) |
87 | |
88 | poll.positions = msgs |
89 | .filter(msg => msg.value.content.root === poll.key) |
90 | .filter(isPosition[type]) |
91 | .map(position => { |
92 | return decoratePosition({position, poll}) |
93 | }) |
94 | |
95 | poll.errors = msgs |
96 | .filter(msg => msg.value.content.root === poll.key) |
97 | .filter(msg => isPosition(msg) && !isPosition[type](msg)) |
98 | .map(position => { |
99 | return { |
100 | type: ERROR_POSITION_TYPE, |
101 | message: `Position responses need to be off the ${type} type for this poll`, |
102 | position |
103 | } |
104 | }) |
105 | |
106 | const {results, errors} = buildResults({ poll, positions: poll.positions }) |
107 | poll.results = results |
108 | poll.errors = poll.errors.concat(errors) |
109 | |
110 | return poll |
111 | } |
112 | |
113 | function decoratePosition ({position: rawPosition, poll: rawPoll}) { |
114 | var position = getContent(rawPosition) |
115 | var poll = getContent(rawPoll) |
116 | |
117 | // NOTE this isn't deep enough to be a safe clone |
118 | var newPosition = Object.assign({}, rawPosition) |
119 | newPosition.reason = position.reason |
120 | |
121 | if (isPoll.chooseOne(poll)) { |
122 | var choiceIndex = position.details.choice |
123 | newPosition.choice = poll.details.choices[choiceIndex] |
124 | } |
125 | return newPosition |
126 | } |
127 |
Built with git-ssb-web