UNPKG

consensus

Version:

vote for topics for your next meeting

236 lines (199 loc) 4.22 kB
var _ = require('lodash'), assert = require('assert'), P = require('p-promise'), polyclay = require('polyclay'), through = require('through'), utilities = require('./utilities'), Vote = require('./Vote'), moment = require('moment') ; moment().format(); var Topic = module.exports = polyclay.Model.buildClass( { properties: { key: 'string', owner: 'reference', agenda: 'reference', created: 'date', modified: 'date', title: 'string', description: 'string', tally: 'number', }, enumerables: { state: ['open', 'closed'] }, required: [ 'key', 'title', 'owner' ], singular: 'topic', plural: 'topics', }); polyclay.persist(Topic, 'key'); Topic.prototype.closed = function() { return this.state === 'closed'; }; Topic.create = function create(opts) { assert(opts, 'you must pass an options object to Topic.create()'); assert(opts.owner, 'you must pass opts.owner to Topic.create()'); assert(opts.agenda, 'you must pass opts.agenda to Topic.create()'); var topic = new Topic(); topic.key = opts.agenda.key + ':' + utilities.randomID(5); topic.created = Date.now(); topic.modified = topic.created; topic.owner = opts.owner; topic.agenda = opts.agenda; topic.title = opts.title; topic.description = opts.description; topic.tally = 0; topic.state = 'open'; return topic.save() .then(function() { return topic; }); }; Topic.prototype.recordVote = function(state) { switch (state) { case 'mu': break; case 'flag': break; case 'yes': this.tally++; break; case 'no': this.tally--; break; default: // wtf } return this.save(); }; Topic.prototype.rollback = function(newstate, oldstate) { if (newstate === oldstate) return P('OK'); if (oldstate === 'yea') this.tally--; else if (oldstate === 'nay') this.tally++; return P('OK'); }; Topic.prototype.votes = function votes() { var self = this, deferred = P.defer(); var votedb = Vote.adapter.objects; var keys = []; votedb.createKeyStream({ start: this.key + ':', end: this.key + '}'}) .on('data', function(key) { keys.push(key); }) .on('end', function() { Vote.get(keys, function(err, votes) { if (err) return deferred.reject(err); deferred.resolve(votes); }) }) .on('error', function(err) { deferred.reject(err); }); return deferred.promise; }; Topic.prototype.voters = function getVoters() { var self = this, deferred = P.defer(); var votedb = Vote.adapter.objects; var voters = []; votedb.createKeyStream({ start: this.key + ':', end: this.key + '}'}) .on('data', function(key) { var parts = key.split(':'); if (!parts || parts.length === 1) parts = key.split('|'); if ((parts.length == 3) && parts[2].length) voters.push(parts[2]); }) .on('end', function() { deferred.resolve(voters); }) .on('error', function(err) { deferred.reject(err); }); return deferred.promise; }; Topic.prototype.proposedWhen = function proposedWhen() { return moment(this.created).fromNow(); }; Topic.prototype.obliterate = function() { var self = this, deferred = P.defer(); var actions = []; var votedb = Vote.adapter.objects; votedb.createKeyStream({ start: this.key + ':', end: this.key + '}'}) .on('data', function(key) { actions.push({ type: 'del', key: key}); }) .on('end', function() { votedb.batch(actions, function(err) { if (err) return deferred.reject(err); self.destroy() .then(function() { deferred.resolve('OK'); }) .fail(function(err) { deferred.reject(err); }).done(); }); }) .on('error', function(err) { deferred.reject(err); }); return deferred.promise; }; Topic.destroyBatch = function(topics) { var actions = _.each(topics, function(t) { return t.obliterate(); }); return P.allSettled(actions); }; Topic.stream = function() { var thruStream = through(); Topic.adapter.objects.createReadStream() .on('data', function (data) { thruStream.queue(JSON.stringify(data.value) + '\n'); }) .on('error', function (err) { thruStream.end(); }) .on('end', function () { thruStream.end(); }); return thruStream; };