Files: 15faa252573d24fb834a5b13c7db4411cf2edb21 / poll / async / get.js
3564 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, isPollUpdate, isChooseOnePosition, parsePollUpdate } = 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 | const myKey = server.id |
14 | |
15 | server.get(key, (err, value) => { |
16 | if (err) return cb(err) |
17 | |
18 | var poll = { key, value } |
19 | if (!isPoll(poll)) return cb(new Error('scuttle-poll could not get poll, key provided was not a valid poll key')) |
20 | |
21 | pull( |
22 | createBacklinkStream(key), |
23 | pull.collect((err, msgs) => { |
24 | if (err) return cb(err) |
25 | |
26 | cb(null, decoratePoll(poll, msgs, myKey)) |
27 | }) |
28 | ) |
29 | }) |
30 | } |
31 | |
32 | function createBacklinkStream (key) { |
33 | var filterQuery = { |
34 | $filter: { |
35 | dest: key |
36 | } |
37 | } |
38 | |
39 | return server.backlinks.read({ |
40 | query: [filterQuery], |
41 | index: 'DTA' // use asserted timestamps |
42 | }) |
43 | } |
44 | } |
45 | |
46 | function decoratePoll (rawPoll, msgs = [], myKey) { |
47 | const { |
48 | author, |
49 | content: { |
50 | title, |
51 | body, |
52 | channel, |
53 | details: { type } |
54 | }, |
55 | recps, |
56 | mentions |
57 | } = rawPoll.value |
58 | |
59 | const poll = Object.assign({}, rawPoll, { |
60 | type, |
61 | author, |
62 | title, |
63 | body, |
64 | channel, |
65 | recps, |
66 | mentions, |
67 | |
68 | actions: { |
69 | publishPosition |
70 | }, |
71 | positions: [], |
72 | results: {}, |
73 | errors: [], |
74 | decorated: true |
75 | }) |
76 | |
77 | function publishPosition (opts, cb) { |
78 | if (poll.type === CHOOSE_ONE) { |
79 | publishChooseOnePosition({ |
80 | poll, |
81 | choice: opts.choice, |
82 | reason: opts.reason |
83 | }, cb) |
84 | } |
85 | } |
86 | |
87 | function doesMsgRefPoll (msg) { |
88 | return msg.value.content.root === poll.key |
89 | } |
90 | |
91 | // TODO add missingContext warnings to each msg |
92 | msgs = sort(msgs) |
93 | |
94 | const latestClosingTime = msgs |
95 | .filter(doesMsgRefPoll) |
96 | .filter(isPollUpdate) |
97 | .map(msg => parsePollUpdate(msg).closesAt) |
98 | .pop() |
99 | |
100 | if (latestClosingTime) poll.closesAt = latestClosingTime |
101 | |
102 | poll.positions = msgs |
103 | .filter(doesMsgRefPoll) |
104 | .filter(isPosition[type]) |
105 | .map(position => { |
106 | return decoratePosition({position, poll}) |
107 | }) |
108 | |
109 | poll.myPosition = poll.positions |
110 | .filter(p => p.value.author === myKey) |
111 | .sort((a, b) => { |
112 | return a.value.timestamp > b.value.timestamp ? -1 : +1 |
113 | })[0] |
114 | |
115 | poll.errors = msgs |
116 | .filter(doesMsgRefPoll) |
117 | .filter(msg => isPosition(msg) && !isPosition[type](msg)) |
118 | .map(position => { |
119 | return { |
120 | type: ERROR_POSITION_TYPE, |
121 | message: `Position responses need to be off the ${type} type for this poll`, |
122 | position |
123 | } |
124 | }) |
125 | |
126 | const {results, errors} = buildResults({ poll, positions: poll.positions }) |
127 | poll.results = results |
128 | poll.errors = poll.errors.concat(errors) |
129 | |
130 | return poll |
131 | } |
132 | |
133 | function decoratePosition ({position: rawPosition, poll: rawPoll}) { |
134 | var position = getContent(rawPosition) |
135 | var poll = getContent(rawPoll) |
136 | |
137 | // NOTE this isn't deep enough to be a safe clone |
138 | var newPosition = Object.assign({}, rawPosition) |
139 | newPosition.reason = position.reason |
140 | |
141 | if (isPoll.chooseOne(poll)) { |
142 | var choiceIndex = position.details.choice |
143 | newPosition.choice = poll.details.choices[choiceIndex] |
144 | } |
145 | return newPosition |
146 | } |
147 |
Built with git-ssb-web