void Voting::valid_motion(const Vote &vote) { const auto &cfg(vote.get_cfg()); const auto &user(vote.get_user()); const auto &chan(vote.get_chan()); valid_limits(vote,chan,user); if(!speaker(cfg,chan,user)) throw Exception("You are not able to create votes on this channel."); if(!enfranchised(cfg,chan,user)) throw Exception("You are not yet enfranchised in this channel."); if(!qualified(cfg,chan,user)) throw Exception("You have not been participating enough to start a vote."); const auto now(time(nullptr)); if(cfg.has("limit.motion")) { const auto limit(secs_cast(cfg["limit.motion"])); const Vdb::Terms query { Vdb::Term { "ended", ">=", lex_cast(now - limit) }, Vdb::Term { "issue", "==", vote.get_issue() }, Vdb::Term { "type", "==", vote.get_type() }, Vdb::Term { "chan", "==", chan.get_name() }, }; if(!vdb.query(query,1).empty()) throw Exception("This vote was made within the last ") << secs_cast(limit) << ". Try again later."; } const Adoc reasons(cfg.get_child("limit.reason",Adoc{})); reasons.for_each([this,&chan,&vote,&now] (const std::string &reason, const std::string &limit_str) { if(reason.size() > 64 || !isalpha(reason)) throw Exception("Malformed reason key given in limit.reason"); const auto limit(secs_cast(limit_str)); const Vdb::Terms query { Vdb::Term { "reason", "==", reason }, Vdb::Term { "ended", ">=", lex_cast(now - limit) }, Vdb::Term { "issue", "==", vote.get_issue() }, Vdb::Term { "type", "==", vote.get_type() }, Vdb::Term { "chan", "==", chan.get_name() }, }; if(!vdb.query(query,1).empty()) throw Exception("This vote failed with the reason '") << reason << "' within the last " << secs_cast(limit) << ". Try again later."; }); }
id_t Voting::duplicated(const Vote &vote) const { const auto pit(chanidx.equal_range(vote.get_chan_name())); for(auto it(pit.first); it != pit.second; ++it) { const auto id(it->second); const auto vit(votes.find(id)); if(vit == votes.end()) continue; const auto &existing(*vit->second); if(vote.get_id() == existing.get_id()) continue; if(vote.get_type() != existing.get_type()) continue; if(!boost::iequals(vote.get_issue(),existing.get_issue())) continue; return existing.get_id(); }; return 0; }
void Voting::valid_limits_type(const Vote &vote, const Chan &chan, const User &user, const Adoc &cfg) { using limits = std::numeric_limits<uint8_t>; if(vote.get_type() == "appeal") return; if(vote.get_type() == "trial") return; auto typcnt(0); for_each(chan,user,[&typcnt,&vote] (const Vote &active) { typcnt += active.get_type() == vote.get_type(); }); if(typcnt > cfg.get<uint8_t>("limit.type",limits::max())) throw Exception("Too many active votes of this type started by you on this channel."); }