Support multiple concurrent votes
This commit is contained in:
parent
d4391cc6c5
commit
96d2a1fae6
1 changed files with 72 additions and 61 deletions
133
modules/vote.py
133
modules/vote.py
|
@ -1,46 +1,58 @@
|
||||||
import binascii, os, uuid
|
import binascii, functools, operator, os, uuid
|
||||||
from src import ModuleManager, utils
|
from src import ModuleManager, utils
|
||||||
|
|
||||||
STR_NOVOTE = "There is currently no vote running."
|
STR_NOVOTE = "Unknown vote '%s'"
|
||||||
|
|
||||||
class Module(ModuleManager.BaseModule):
|
class Module(ModuleManager.BaseModule):
|
||||||
def _get_vote(self, channel):
|
def _get_vote(self, channel, vote_id):
|
||||||
return channel.get_setting("vote", None)
|
return channel.get_setting("vote-%s" % vote_id, None)
|
||||||
def _set_vote(self, channel, vote):
|
def _set_vote(self, channel, vote_id, vote):
|
||||||
channel.set_setting("vote", vote)
|
channel.set_setting("vote-%s" % vote_id, vote)
|
||||||
def _del_vote(self, channel):
|
|
||||||
channel.del_setting("vote")
|
|
||||||
|
|
||||||
def _add_archive_vote(self, channel, vote, id):
|
|
||||||
channel.set_setting("vote-%s" % id, vote)
|
|
||||||
def _get_archive_vote(self, channel, id):
|
|
||||||
return channel.get_setting("vote-%s" % id, None)
|
|
||||||
|
|
||||||
def _random_id(self):
|
def _random_id(self):
|
||||||
return binascii.hexlify(os.urandom(4)).decode("ascii")
|
return binascii.hexlify(os.urandom(4)).decode("ascii")
|
||||||
def _archive_vote(self, channel):
|
|
||||||
vote = self._get_vote(channel)
|
def _close_vote(self, channel, vote_id):
|
||||||
|
vote = self._get_vote(channel, vote_id)
|
||||||
|
if vote:
|
||||||
|
vote["open"] = False
|
||||||
|
self._set_vote(channel, vote_id, vote)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _start_vote(self, channel, description):
|
||||||
vote_id = self._random_id()
|
vote_id = self._random_id()
|
||||||
self._add_archive_vote(channel, vote, vote_id)
|
vote = {"description": description, "options": {"yes": [], "no": []},
|
||||||
self._del_vote(channel)
|
"electorate": [], "open": True, "id": vote_id}
|
||||||
return vote_id
|
self._set_vote(channel, vote_id, vote)
|
||||||
|
return vote
|
||||||
|
|
||||||
def _format_vote(self, vote):
|
def _format_vote(self, vote):
|
||||||
return "%s (%s yes, %s no)" % (vote["description"], len(vote["yes"]),
|
options = ["%d %s" % (len(v), k) for k, v in vote["options"].items()]
|
||||||
len(vote["no"]))
|
return "%s (%s)" % (vote["description"], ", ".join(options))
|
||||||
|
def _format_options(self, vote):
|
||||||
|
return ", ".join("'%s'" % o for o in vote["options"])
|
||||||
|
|
||||||
def _cast_vote(self, channel, user, yes):
|
def _cast_vote(self, channel, vote_id, user, option):
|
||||||
vote = self._get_vote(channel)
|
vote = self._get_vote(channel, vote_id)
|
||||||
key = "yes" if yes else "no"
|
option = vote["options"][option]
|
||||||
voters = vote["yes"]+vote["no"]
|
voters = functools.reduce(operator.concat,
|
||||||
|
list(vote["options"].values()))
|
||||||
|
|
||||||
if user.name in voters:
|
if user.name in voters:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
vote[key].append(user.name)
|
option.append(user.name)
|
||||||
self._set_vote(channel, vote)
|
self._set_vote(channel, vote_id, vote)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _open_votes(self, channel):
|
||||||
|
open = []
|
||||||
|
for setting, vote in channel.find_settings_prefix("vote-"):
|
||||||
|
if vote["open"]:
|
||||||
|
open.append(vote)
|
||||||
|
return open
|
||||||
|
|
||||||
@utils.hook("received.command.startvote", channel_only=True, min_args=1)
|
@utils.hook("received.command.startvote", channel_only=True, min_args=1)
|
||||||
def start_vote(self, event):
|
def start_vote(self, event):
|
||||||
"""
|
"""
|
||||||
|
@ -49,66 +61,65 @@ class Module(ModuleManager.BaseModule):
|
||||||
:require_mode: o
|
:require_mode: o
|
||||||
:permission: vote
|
:permission: vote
|
||||||
"""
|
"""
|
||||||
current_vote = self._get_vote(event["target"])
|
vote = self._start_vote(event["target"], event["args"])
|
||||||
if not current_vote == None:
|
|
||||||
raise utils.EventError("There's already a vote running")
|
|
||||||
|
|
||||||
self._set_vote(event["target"], {"description": event["args"],
|
|
||||||
"yes": [], "no": [], "electorate": []})
|
|
||||||
event["stdout"].write(
|
event["stdout"].write(
|
||||||
"Vote started. use '%svote yes' or '%svote no' to vote." % (
|
"Vote %s started. use '%svote <option>' to vote (options: %s)" %
|
||||||
event["command_prefix"], event["command_prefix"]))
|
(vote["id"], event["command_prefix"], self._format_options(vote)))
|
||||||
|
|
||||||
@utils.hook("received.command.endvote", channel_only=True)
|
@utils.hook("received.command.endvote", channel_only=True, min_args=1)
|
||||||
def end_vote(self, event):
|
def end_vote(self, event):
|
||||||
"""
|
"""
|
||||||
:help: End the current yes/no vote
|
:help: End the current yes/no vote
|
||||||
|
:usage: <id>
|
||||||
:require_mode: o
|
:require_mode: o
|
||||||
:permission: vote
|
:permission: vote
|
||||||
"""
|
"""
|
||||||
vote = self._get_vote(event["target"])
|
vote_id = event["args_split"][0]
|
||||||
if vote == None:
|
|
||||||
event["stderr"].write(STR_NOVOTE)
|
if self._close_vote(event["target"], vote_id):
|
||||||
else:
|
vote = self._get_vote(event["target"], vote_id)
|
||||||
vote_id = self._archive_vote(event["target"])
|
|
||||||
event["stdout"].write("Vote %s ended: %s" %
|
event["stdout"].write("Vote %s ended: %s" %
|
||||||
(vote_id, self._format_vote(vote)))
|
(vote_id, self._format_vote(vote)))
|
||||||
|
else:
|
||||||
|
event["stderr"].write(STR_NOVOTE % vote_id)
|
||||||
|
|
||||||
@utils.hook("received.command.vote", channel_only=True)
|
@utils.hook("received.command.vote", channel_only=True, min_args=1)
|
||||||
def vote(self, event):
|
def vote(self, event):
|
||||||
"""
|
"""
|
||||||
:help: Vote in the channel's current vote
|
:help: Vote in the channel's current vote
|
||||||
:usage: yes|no
|
:usage: <id> yes|no
|
||||||
"""
|
"""
|
||||||
vote = self._get_vote(event["target"])
|
vote_id = event["args_split"][0]
|
||||||
|
vote = self._get_vote(event["target"], vote_id)
|
||||||
if vote == None:
|
if vote == None:
|
||||||
raise utils.EventError(STR_NOVOTE)
|
raise utils.EventError(STR_NOVOTE % vote_id)
|
||||||
|
|
||||||
if not event["args"]:
|
if not len(event["args_split"]) > 1:
|
||||||
event["stdout"].write("Current vote: %s)" % self._format_vote(vote))
|
closed = "" if vote["open"] else " (closed)"
|
||||||
|
event["stdout"].write("Vote %s%s: %s" % (
|
||||||
|
vote_id, closed, self._format_vote(vote)))
|
||||||
else:
|
else:
|
||||||
choice = event["args_split"][0].lower()
|
choice = event["args_split"][1].lower()
|
||||||
if not choice in ["yes", "no"]:
|
if not choice in vote["options"]:
|
||||||
raise utils.EventError("Please vote 'yes' or 'no'")
|
raise utils.EventError("Vote options: %s" %
|
||||||
|
self._format_options(vote))
|
||||||
|
|
||||||
if self._cast_vote(event["target"], event["user"], choice=="yes"):
|
if self._cast_vote(event["target"], vote_id, event["user"], choice):
|
||||||
event["stdout"].write("%s: your vote has been cast." %
|
event["stdout"].write("%s: your vote has been cast." %
|
||||||
event["user"].nickname)
|
event["user"].nickname)
|
||||||
else:
|
else:
|
||||||
event["stderr"].write("%s: you have already voted." %
|
event["stderr"].write("%s: you have already voted." %
|
||||||
event["user"].nickname)
|
event["user"].nickname)
|
||||||
|
|
||||||
@utils.hook("received.command.getvote", min_args=1)
|
@utils.hook("received.command.votes", channel_only=True)
|
||||||
def get_vote(self, event):
|
def votes(self, event):
|
||||||
"""
|
"""
|
||||||
:help: Show stats for a previous vote
|
:help: List open votes in the current channel
|
||||||
:usage: <id>
|
|
||||||
"""
|
"""
|
||||||
vote_id = event["args_split"][0].lower()
|
open_votes = self._open_votes(event["target"])
|
||||||
vote = self._get_archive_vote(event["target"], vote_id)
|
if open_votes:
|
||||||
|
open_votes_str = [
|
||||||
if vote == None:
|
"%s (%s)" % (v["description"], v["id"]) for v in open_votes]
|
||||||
event["stderr"].write("Unknown vote '%s'" % vote_id)
|
event["stdout"].write("Open votes: %s" % ", ".join(open_votes_str))
|
||||||
else:
|
else:
|
||||||
event["stdout"].write("Vote %s: %s" % (vote_id,
|
event["stderr"].write("There are no open votes")
|
||||||
self._format_vote(vote)))
|
|
||||||
|
|
Loading…
Reference in a new issue