git ssb

0+

Piet / ssb-loomio



Tree: 1502f0ba17e8680d8ec32ad7bf6195d105d75f6a

Files: 1502f0ba17e8680d8ec32ad7bf6195d105d75f6a / poll / async / get.js

3564 bytesRaw
1const pull = require('pull-stream')
2const sort = require('ssb-sort')
3const getContent = require('ssb-msg-content')
4const { isPoll, isPosition, isChooseOnePoll, isPollUpdate, isChooseOnePosition, parsePollUpdate } = require('ssb-poll-schema')
5isPoll.chooseOne = isChooseOnePoll
6isPosition.chooseOne = isChooseOnePosition
7const buildResults = require('../../results/sync/buildResults')
8const { CHOOSE_ONE, ERROR_POSITION_TYPE } = require('../../types')
9const publishChooseOnePosition = require('../../position/async/buildChooseOne')
10
11module.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
46function 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
133function 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