git ssb

0+

Piet / ssb-loomio



Commit 4ae9c2d21f4b6d8fc91aeb1a890c40180b8a4c7f

Merge branch 'master' of github.com:ssbc/scuttle-poll into poll.async.get

mix irving committed on 3/7/2018, 2:10:31 AM
Parent: 9db352a29a6d5bac4344c081e9228bd03aaeb97c
Parent: da135887bee9c9d5aa3136c5eec07ede25ed84b6

Files changed

package-lock.jsonchanged
package.jsonchanged
position/sync/position.jschanged
position/sync/chooseOneResults.jsadded
test/position/sync/chooseOneResults.test.jsadded
types.jschanged
package-lock.jsonView
@@ -281,12 +281,11 @@
281281 "resolved": "https://registry.npmjs.org/is-valid-domain/-/is-valid-domain-0.0.5.tgz",
282282 "integrity": "sha1-SOcDGfy0MAkjbpazf5hDiJzntRM="
283283 },
284284 "isarray": {
285- "version": "1.0.0",
286- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
287- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
288- "dev": true
285+ "version": "2.0.4",
286+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz",
287+ "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA=="
289288 },
290289 "jsonpointer": {
291290 "version": "4.0.1",
292291 "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
@@ -428,8 +427,16 @@
428427 "process-nextick-args": "2.0.0",
429428 "safe-buffer": "5.1.1",
430429 "string_decoder": "1.0.3",
431430 "util-deprecate": "1.0.2"
431+ },
432+ "dependencies": {
433+ "isarray": {
434+ "version": "1.0.0",
435+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
436+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
437+ "dev": true
438+ }
432439 }
433440 },
434441 "repeat-string": {
435442 "version": "1.6.1",
package.jsonView
@@ -28,8 +28,9 @@
2828 "tape": "^4.8.0"
2929 },
3030 "dependencies": {
3131 "is-my-json-valid": "^2.17.1",
32+ "isarray": "^2.0.4",
3233 "libnested": "^1.2.1",
3334 "lodash.clonedeep": "^4.5.0",
3435 "ssb-msg-schemas": "^6.3.0",
3536 "ssb-ref": "^2.9.0"
position/sync/position.jsView
@@ -1,7 +1,9 @@
11 // var { link } = require('ssb-msg-schemas/util')
2+var getMsgContent = require('../../lib/getMsgContent')
23
3-function Position ({ poll, positionDetails, reason, channel, recps, mentions }) {
4+function Position (msg) {
5+ var { poll, positionDetails, reason, channel, recps, mentions } = getMsgContent(msg)
46 var content = { type: 'position', poll, positionDetails, reason }
57
68 // if (root) {
79 // root = link(root)
position/sync/chooseOneResults.jsView
@@ -1,0 +1,46 @@
1+const isArray = require('isarray')
2+const Position = require('../../position/sync/position')
3+const {ERROR_POSITION_CHOICE, ERROR_POSITION_TYPE, ERROR_POSITION_LATE} = require('../../types')
4+
5+// Expects `poll` and `position` objects passed in to be of shape:
6+// {
7+// value: {
8+// content: {...},
9+// timestamp: ...
10+// author: ...
11+// }
12+// }
13+//
14+// postions must be of the correct type ie: type checked by the caller.
15+module.exports = function chooseOneResults ({positions, poll}) {
16+ return positions.reduce(function (results, position) {
17+ const { value: {author} } = position
18+ const { positionDetails: {choice} } = Position(position)
19+
20+ if (isInvalidChoice({position, poll})) {
21+ results.errors.push({type: ERROR_POSITION_CHOICE, position})
22+ return results
23+ }
24+
25+ if (isPositionLate({position, poll})) {
26+ results.errors.push({type: ERROR_POSITION_LATE, position})
27+ return results
28+ }
29+
30+ if (!isArray(results[choice])) {
31+ results[choice] = []
32+ }
33+ results[choice].push(author)
34+
35+ return results
36+ }, {errors: []})
37+}
38+
39+function isInvalidChoice ({position, poll}) {
40+ const { positionDetails: {choice} } = Position(position)
41+ return choice >= poll.pollDetails.choices.length
42+}
43+
44+function isPositionLate ({position, poll}) {
45+ return position.value.timestamp > poll.closesAt
46+}
test/position/sync/chooseOneResults.test.jsView
@@ -1,0 +1,90 @@
1+const test = require('tape')
2+const ChooseOne = require('../../../position/sync/chooseOne')
3+const ChooseOnePoll = require('../../../poll/sync/chooseOne')
4+const Position = require('../../../position/sync/position')
5+const chooseOneResults = require('../../../position/sync/chooseOneResults')
6+const {ERROR_POSITION_CHOICE, ERROR_POSITION_TYPE, ERROR_POSITION_LATE} = require('../../../types')
7+
8+const pietId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/0=.ed25519'
9+const mixId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/1=.ed25519'
10+const mikeyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/2=.ed25519'
11+const timmyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/3=.ed25519'
12+const tommyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/4=.ed25519'
13+const sallyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/5=.ed25519'
14+
15+const poll = '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256'
16+
17+const now = Number(new Date())
18+
19+const validPoll = ChooseOnePoll({
20+ choices: [1, 2, 'three'],
21+ title: 'how many food',
22+ closesAt: now
23+})
24+
25+test('ChooseOneResults - ChooseOneResults', function (t) {
26+ const positions = [
27+ { value: { content: Position(ChooseOne({choice: 0, poll})), author: pietId } },
28+ { value: { content: Position(ChooseOne({choice: 0, poll})), author: mixId } },
29+ { value: { content: Position(ChooseOne({choice: 0, poll})), author: mikeyId } },
30+ { value: { content: Position(ChooseOne({choice: 1, poll})), author: timmyId } },
31+ { value: { content: Position(ChooseOne({choice: 1, poll})), author: tommyId } },
32+ { value: { content: Position(ChooseOne({choice: 2, poll})), author: sallyId } }
33+ ]
34+
35+ const actual = chooseOneResults({positions, poll: validPoll})
36+ t.deepEqual(actual[0], [pietId, mixId, mikeyId], 'correct voters for choice 0')
37+ t.deepEqual(actual[1], [timmyId, tommyId], 'correct voters for choice 1')
38+ t.deepEqual(actual[2], [sallyId], 'correct voters for choice 2')
39+ t.end()
40+})
41+
42+test('ChooseOneResults - a position stated for an invalid choice index is not counted', function (t) {
43+ const positions = [
44+ { value: { content: Position(ChooseOne({choice: 3, poll})), author: pietId } }
45+ ]
46+
47+ const actual = chooseOneResults({positions, poll: validPoll})
48+ t.false(actual[3], 'invalid vote is not counted')
49+ t.end()
50+})
51+
52+test('ChooseOneResults - a position stated for an invalid choice index is included in the errors object', function (t) {
53+ const positions = [
54+ { value: { content: Position(ChooseOne({choice: 3, poll})), author: pietId } }
55+ ]
56+
57+ const actual = chooseOneResults({positions, poll: validPoll})
58+ t.deepEqual(actual.errors[0].type, ERROR_POSITION_CHOICE, 'invalid vote is on error object')
59+ t.end()
60+})
61+
62+test('ChooseOneResults - A position stated before the closing time of the poll is counted', function (t) {
63+ const positions = [
64+ { value: { content: Position(ChooseOne({choice: 0, poll})), author: pietId, timestamp: now - 1} }
65+ ]
66+
67+ const actual = chooseOneResults({positions, poll: validPoll})
68+ t.true(actual[0], 'valid vote is counted')
69+ t.end()
70+})
71+
72+test('ChooseOneResults - A position stated after the closing time of the poll is not counted', function (t) {
73+ const positions = [
74+ { value: { content: Position(ChooseOne({choice: 0, poll})), author: pietId, timestamp: now + 1} }
75+ ]
76+
77+ const actual = chooseOneResults({positions, poll: validPoll})
78+ t.false(actual[0], 'invalid vote is not counted')
79+ t.end()
80+})
81+
82+test('ChooseOneResults - A position stated after the closing time of the poll is included in the error object', function (t) {
83+ const positions = [
84+ { value: { content: Position(ChooseOne({choice: 0, poll})), author: pietId, timestamp: now + 1} }
85+ ]
86+
87+ const actual = chooseOneResults({positions, poll: validPoll})
88+ t.deepEqual(actual.errors[0].type, ERROR_POSITION_LATE, 'invalid vote is on error object')
89+ t.end()
90+})
types.jsView
@@ -1,6 +1,9 @@
11 module.exports = {
2- CHOOSE_ONE: 'chooseOne'
2+ CHOOSE_ONE: 'chooseOne',
3+ ERROR_POSITION_TYPE: 'ERROR_POSITION_TYPE',
4+ ERROR_POSITION_LATE: 'ERROR_POSITION_LATE',
5+ ERROR_POSTITION_CHOICE: 'ERROR_POSTITION_CHOICE'
36 }
47
58 // Question: do these need to be different, could we just have 'chooseOne',
69 // because we already have:

Built with git-ssb-web