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."; }); }
void Voting::cancel(Vote &vote, const Chan &chan, const User &user) { if(user.get_acct() != vote.get_user_acct()) throw Exception() << "You can't cancel a vote by " << vote.get_user_acct() << "."; if(vote.total() > 1) throw Exception("You can't cancel after someone else has voted."); const auto &cfg(vote.get_cfg()); if(!cfg.get("cancel",true)) throw Exception("You can't cancel votes of this type."); vote.cancel(); del(vote.get_id()); }
void Voting::valid_limits(const Vote &vote, const Chan &chan, const User &user) { using limits = std::numeric_limits<uint8_t>; if(user.is_myself() || chan.users.mode(user).has('o')) return; const auto &cfg(vote.get_cfg()); if(count(chan) > cfg.get<uint8_t>("limit.active",limits::max())) throw Exception("Too many active votes for this channel."); if(count(chan,user) > cfg.get<uint8_t>("limit.user",limits::max())) throw Exception("Too many active votes started by you on this channel."); valid_limits_type(vote,chan,user,cfg); }