consensus
Version:
vote for topics for your next meeting
807 lines (718 loc) • 17.1 kB
JavaScript
var
Agenda = require('../lib/Agenda'),
Topic = require('../lib/Topic'),
Vote = require('../lib/Vote'),
Person = require('../lib/Person'),
marked = require('marked'),
util = require('util')
;
exports.index = function(request, response)
{
var locals =
{
title: 'Consensus',
agendas: []
};
Agenda.all()
.then(function(agendas)
{
locals.agendas = agendas;
response.render('index', locals);
})
.fail(function(err)
{
request.app.logger.error(err, 'error fetching agendas');
request.flash('error', 'Warning: couldn\'t fetch agendas.');
response.render('index', locals);
}).done();
};
exports.relevantAgendas = function(request, response)
{
var locals = {};
var owner = response.locals.authed_user;
if (!owner)
{
response.redirect('/');
return;
}
owner.fetchAgendas()
.then(function(agendas)
{
locals.agendas = agendas;
response.render('agendas-mine', locals);
})
.fail(function(err)
{
request.flash('error', err.message);
response.redirect('/');
}).done();
};
exports.agenda = function(request, response)
{
var locals = {};
Agenda.get(request.params.id)
.then(function(agenda)
{
locals.agenda = agenda;
locals.title = agenda.title;
locals.description = marked(agenda.description);
return agenda.fetchTopics();
})
.then(function(topics)
{
locals.agenda.topics = topics;
response.render('agenda', locals);
})
.fail(function(err)
{
response.app.logger.error(err);
request.flash('error', 'That agenda doesn\'t exist.');
response.redirect('/');
}).done();
};
exports.presentAgenda = function(request, response)
{
var locals = {};
var people = {};
Agenda.get(request.params.id)
.then(function(agenda)
{
locals.agenda = agenda;
locals.title = agenda.title;
locals.description = marked(agenda.description);
people[agenda.owner_id] = true;
return agenda.fetchTopics();
})
.then(function(topics)
{
locals.topics = topics.open;
for (var i = 0; i < locals.topics.length; i++)
{
var t = locals.topics[i];
people[t.owner_id] = true;
}
return Person.get(Object.keys(people));
})
.then(function(proposers)
{
for (var i = 0; i < proposers.length; i++)
people[proposers[i].key] = proposers[i];
locals.tjson = [];
for (i = 0; i < locals.topics.length; i++)
{
var t = locals.topics[i].toJSON();
t.description = marked(t.description);
t.owner = people[t.owner_id].toJSON();
locals.tjson.push(t);
}
response.render('agenda-present', locals);
})
.fail(function(err)
{
response.app.logger.error(err);
request.flash('error', 'That agenda doesn\'t exist.');
response.redirect('/');
}).done();
};
exports.newAgenda = function(request, response)
{
response.render('agenda-edit',
{
title: 'New agenda',
});
};
exports.handleNewAgenda = function(request, response)
{
var owner = response.locals.authed_user;
var opts =
{
title: request.sanitize('ititle').xss(),
description: request.sanitize('idesc').xss(),
owner: owner
};
var agenda;
Agenda.create(opts)
.then(function(created)
{
agenda = created;
return owner.addAgenda(agenda.key);
})
.then(function()
{
request.flash('success', 'Agenda created.');
response.redirect('/agendas/' + agenda.key);
}).fail(function(err)
{
response.app.logger.error(err);
request.flash('error', err.message);
response.render('agenda-edit',
{
title: 'New agenda',
ititle: opts.title,
idesc: opts.description,
});
}).done();
};
exports.editAgenda = function(request, response)
{
var owner = response.locals.authed_user;
var locals = {};
Agenda.get(request.params.id)
.then(function(agenda)
{
if (!agenda)
{
request.flash('error', 'That agenda can\'t be found.');
response.redirect('/');
return;
}
if (agenda.owner_id !== owner.email)
{
request.flash('error', 'That agenda doesn\'t belong to you.');
response.redirect('/');
return;
}
locals.agenda = agenda;
locals.title = agenda.title;
locals.ititle = agenda.title;
locals.idesc = agenda.description;
response.render('agenda-edit', locals);
}).fail(function(err)
{
response.app.logger.error(err);
request.flash('error', err.message);
response.redirect('/');
}).done();
};
exports.handleEditAgenda = function(request, response)
{
var owner = response.locals.authed_user;
Agenda.get(request.params.id)
.then(function(agenda)
{
if (!agenda)
{
request.flash('error', 'That agenda can\'t be found.');
response.redirect('/');
return;
}
if (agenda.owner_id !== owner.email)
{
request.flash('error', 'That agenda doesn\'t belong to you.');
response.redirect('/');
return;
}
agenda.title = request.sanitize('ititle').xss();
agenda.description = request.sanitize('idesc').xss();
return agenda.save();
})
.then(function()
{
request.flash('Your agenda has been updated.');
response.redirect('/agendas/' + request.params.id);
}).fail(function(err)
{
response.app.logger.error(err);
request.flash('error', err.message);
response.redirect('/');
}).done();
};
exports.handleCloseAgenda = function(request, response)
{
var owner = response.locals.authed_user;
var locals = {};
Agenda.get(request.params.id)
.then(function(agenda)
{
if (!agenda)
{
request.flash('error', 'That agenda can\'t be found.');
response.redirect('/');
return;
}
if (agenda.owner_id !== owner.email)
{
request.flash('error', 'That agenda doesn\'t belong to you.');
response.redirect('/');
return;
}
locals.agenda = agenda;
agenda.active = false;
return agenda.save();
})
.then(function()
{
request.flash('Your agenda has been marked as inactive.');
response.redirect('/agendas/' + request.params.id);
}).fail(function(err)
{
response.app.logger.error(err);
request.flash('error', err.message);
response.redirect('/');
}).done();
};
exports.handleOpenAgenda = function(request, response)
{
var owner = response.locals.authed_user;
var locals = {};
Agenda.get(request.params.id)
.then(function(agenda)
{
if (!agenda)
{
request.flash('error', 'That agenda can\'t be found.');
response.redirect('/');
return;
}
if (agenda.owner_id !== owner.email)
{
request.flash('error', 'That agenda doesn\'t belong to you.');
response.redirect('/');
return;
}
locals.agenda = agenda;
agenda.active = true;
return agenda.save();
})
.then(function()
{
request.flash('Your agenda has been marked as active.');
response.redirect('/agendas/' + request.params.id);
}).fail(function(err)
{
response.app.logger.error(err);
request.flash('error', err.message);
response.redirect('/');
}).done();
};
exports.handleDeleteAgenda = function(request, response)
{
var owner = response.locals.authed_user;
var locals = {};
var agenda;
Agenda.get(request.params.id)
.then(function(found)
{
if (!found)
{
request.flash('error', 'That agenda can\'t be found.');
response.redirect('/');
return;
}
if (found.owner_id !== owner.email)
{
request.flash('error', 'That agenda doesn\'t belong to you.');
response.redirect('/');
return;
}
agenda = found;
return agenda.fetchTopics();
})
.then(function(topics)
{
return Topic.destroyBatch(topics);
})
.then(function()
{
return agenda.destroy();
})
.then(function()
{
request.flash('The agenda "' + agenda.title + '" has been deleted.');
response.redirect('/');
}).fail(function(err)
{
response.app.logger.error(err);
request.flash('error', err.message);
response.redirect('/');
}).done();
};
exports.topic = function(request, response)
{
var owner = response.locals.authed_user;
var locals = {};
Topic.get(request.params.tid)
.then(function(topic)
{
if (!topic)
{
request.app.logger.info('topic not found: ' + request.params.tid);
request.flash('error', 'That topic doesn\'t exist.');
response.redirect('/');
return;
}
locals.topic = topic;
locals.title = topic.title;
locals.description = marked(topic.description);
locals.yes_class = 'btn-default';
locals.no_class = 'btn-default';
locals.flag_class = 'btn-default';
return topic.voters();
})
.then(function(voters)
{
locals.voters = voters;
return Vote.fetchFor(locals.topic, owner);
})
.then(function(vote)
{
if (vote)
{
locals.vote = vote;
switch (vote.state)
{
case 'yes': locals.yes_class = 'btn-success'; break;
case 'no': locals.no_class = 'btn-success'; break;
case 'flag': locals.flag_class = 'btn-danger'; break;
}
}
return Agenda.get(locals.topic.agenda_id);
})
.then(function(agenda)
{
locals.agenda = agenda;
response.render('topic', locals);
})
.fail(function(err)
{
request.app.logger.error('topic() error: ' + request.params.tid, err);
request.flash('error', err.message);
response.redirect('/');
}).done();
};
exports.newTopic = function newTopic(request, response)
{
var aid = request.params.id;
Agenda.get(aid, function(err, agenda)
{
if (err)
{
request.flash('error', 'That agenda doesn\'t exist.');
response.redirect('/');
return;
}
var locals =
{
title: 'New topic',
agenda: agenda,
};
response.render('topic-edit', locals);
});
};
exports.handleNewTopic = function(request, response)
{
var aid = request.params.id;
var owner = response.locals.authed_user;
var topic;
Agenda.get(aid, function(err, agenda)
{
if (err)
{
request.flash('error', 'That agenda doesn\'t exist.');
response.redirect('/');
return;
}
var opts =
{
title: request.sanitize('ititle').xss(),
description: request.sanitize('idesc').xss(),
owner: owner,
agenda: agenda
};
Topic.create(opts)
.then(function(newtopic)
{
topic = newtopic;
return owner.addAgenda(aid);
})
.then(function()
{
request.app.logger.info(topic, 'topic created by ' + owner.key);
request.flash('success', 'Topic created.');
response.redirect('/topics/' + topic.key);
}).fail(function(err)
{
response.app.logger.error(err);
request.flash('error', err.message);
response.render('topic-edit',
{
title: 'New topic',
ititle: opts.title,
idesc: opts.description,
agenda: agenda,
});
}).done();
});
};
exports.editTopic = function(request, response)
{
var owner = response.locals.authed_user;
var locals = { title: 'Edit topic' };
Topic.get(request.params.tid)
.then(function(topic)
{
if (!topic || (Array.isArray(topic) && topic.length === 0))
{
request.app.logger.info('topic not found: ' + request.params.id);
request.flash('error', 'That topic doesn\'t exist.');
response.redirect('/');
return;
}
if (topic.owner_id !== owner.email)
{
request.flash('error', 'You are not authorized to edit that topic.');
response.redirect('/topic/' + topic.key);
return;
}
locals.topic = topic;
locals.ititle = topic.title;
locals.idesc = topic.description;
return Agenda.get(locals.topic.agenda_id);
})
.then(function(agenda)
{
locals.agenda = agenda;
response.render('topic-edit', locals);
})
.fail(function(err)
{
request.app.logger.error('editTopic() error fetching topic: ' + request.params.tid, err);
request.flash('error', err.message);
response.redirect('/');
}).done();
};
exports.handleEditTopic = function(request, response)
{
var owner = response.locals.authed_user;
Topic.get(request.params.tid)
.then(function(topic)
{
if (!topic)
{
request.app.logger.info('topic not found: ' + request.params.id);
request.flash('error', 'That topic doesn\'t exist.');
response.redirect('/');
return;
}
if (topic.owner_id !== owner.email)
{
request.flash('error', 'You are not authorized to edit that topic.');
response.redirect('/topic/' + topic.key);
return;
}
topic.title = request.sanitize('ititle').xss();
topic.description = request.sanitize('idesc').xss();
topic.modified = Date.now();
return topic.save();
})
.then(function()
{
request.flash('success', 'Topic edits saved.');
response.redirect('/topics/' + request.params.tid);
})
.fail(function(err)
{
request.app.logger.error(err, 'handleEditTopic() error fetching topic: ' + request.params.tid);
request.flash('error', err.message);
response.redirect('/topics/' + request.params.tid);
}).done();
};
exports.handleTopicVote = function handleTopicVote(request, response)
{
var owner = response.locals.authed_user;
var topic_id = request.params.tid;
var state = request.params.vote;
var vote;
var isUpdate = false;
var opts =
{
owner: owner,
state: state,
};
Topic.get(topic_id)
.then(function(topic)
{
opts.topic = topic;
return Vote.fetchFor(topic, opts.owner);
})
.then(function(previous)
{
if (previous)
{
vote = previous;
if (opts.state === previous.state)
return false;
return opts.topic.rollback(opts.state, previous.state)
.then(function()
{
vote.state = opts.state;
return vote.save();
})
.then(function()
{
return vote;
});
}
return Vote.create(opts);
})
.then(function(recordThis)
{
if (recordThis)
{
vote = recordThis;
return opts.topic.recordVote(vote.state);
}
})
.then(function()
{
return owner.addAgenda(opts.topic.agenda_id);
})
.then(function()
{
response.app.logger.debug('vote: ' + vote.key + ' -> ' + vote.state);
request.flash('success', 'Your vote has been recorded.');
response.redirect('/topics/' + topic_id);
})
.fail(function(err)
{
response.app.logger.error(err);
request.flash('error', err.message);
response.redirect('/topics/' + topic_id);
}).done();
};
exports.closeTopic = function(request, response)
{
var person = response.locals.authed_user;
var topic_id = request.params.tid;
var opts = { };
Topic.get(topic_id)
.then(function(topic)
{
opts.topic = topic;
return Agenda.get(topic.agenda_id);
})
.then(function(agenda)
{
if ((agenda.owner_id !== person.email) && (topic.owner_id !== person.email))
{
request.flash('error', 'You are not authorized to close that topic.');
response.redirect('/topic/' + opts.topic.key);
return;
}
opts.topic.state = 'closed';
opts.topic.modified = Date.now();
return opts.topic.save();
})
.then(function()
{
response.app.logger.debug('topic: ' + opts.topic.key + ' closed by ' + person.email);
request.flash('success', 'That topic has been marked as closed.');
response.redirect('/agendas/' + opts.topic.agenda_id);
})
.fail(function(err)
{
response.app.logger.error(err);
request.flash('error', err.message);
response.redirect('/topics/' + topic_id);
}).done();
};
exports.handleDeleteTopic = function(request, response)
{
var person = response.locals.authed_user;
var topic_id = request.params.tid;
var opts = {};
Topic.get(topic_id)
.then(function(topic)
{
opts.topic = topic;
return topic.obliterate();
})
.then(function()
{
response.app.logger.debug('topic: ' + opts.topic.key + ' deleted by ' + person.email);
request.flash('success', 'Topic "' + opts.topic.title + '" has been deleted.');
response.redirect('/agendas/' + opts.topic.agenda_id);
})
.fail(function(err)
{
response.app.logger.error(err);
request.flash('error', err.message);
response.redirect('/topics/' + topic_id);
}).done();
};
exports.settings = function(request, response)
{
var avatars = request.app.get('avatars');
response.render('settings',
{
person: response.locals.authed_user,
token: avatars.public,
title: 'Your profile'
});
};
exports.handleSettings = function(request, response)
{
var person = response.locals.authed_user;
if (request.body.iavatar_url)
request.assert('iavatar_url', 'avatar is not a valid url').isUrl();
var errors = request.validationErrors();
if (errors)
{
request.flash('error', util.inspect(errors));
var locals =
{
person: response.locals.authed_user,
title: 'Your profile'
};
response.render('settings', locals);
return;
}
person.name = request.sanitize('iname').xss();
person.description = request.sanitize('idesc').xss();
person.avatar = request.sanitize('iavatar_url').xss();
person.modified = Date.now();
person.save()
.then(function()
{
request.flash('success', 'You have updated your profile.');
response.redirect('/u/' + person.key);
})
.fail(function(err)
{
response.app.logger.error(err);
request.flash('error', err.message);
response.redirect('/settings');
}).done();
};
exports.profile = function(request, response)
{
var locals = {};
var uid = request.params.uid;
Person.personByEmail(uid)
.then(function(person)
{
if (!person)
{
request.flash('warning', 'Profile for ' + uid + ' not found.');
response.redirect('/');
return;
}
locals.person = person;
locals.description = marked(person.description);
return person.fetchAgendas();
})
.then(function(agendas)
{
if (Array.isArray(agendas))
{
locals.agendas = agendas;
response.render('profile', locals);
}
})
.fail(function(err)
{
response.app.logger.error(err);
request.flash('error', err.message);
response.redirect('/');
}).done();
};