bitbot-3.11-fork/modules/vote.py

126 lines
4.5 KiB
Python
Raw Normal View History

2019-06-17 16:51:42 +00:00
import binascii, functools, operator, os, uuid
2019-06-17 15:29:14 +00:00
from src import ModuleManager, utils
2019-06-17 16:51:42 +00:00
STR_NOVOTE = "Unknown vote '%s'"
2019-06-17 15:29:14 +00:00
class Module(ModuleManager.BaseModule):
2019-06-17 16:51:42 +00:00
def _get_vote(self, channel, vote_id):
return channel.get_setting("vote-%s" % vote_id, None)
def _set_vote(self, channel, vote_id, vote):
channel.set_setting("vote-%s" % vote_id, vote)
2019-06-17 15:36:48 +00:00
2019-06-17 15:29:14 +00:00
def _random_id(self):
return binascii.hexlify(os.urandom(4)).decode("ascii")
2019-06-17 16:51:42 +00:00
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):
2019-06-17 15:29:14 +00:00
vote_id = self._random_id()
2019-06-17 16:51:42 +00:00
vote = {"description": description, "options": {"yes": [], "no": []},
"electorate": [], "open": True, "id": vote_id}
self._set_vote(channel, vote_id, vote)
return vote
2019-06-17 15:29:14 +00:00
2019-06-17 15:36:48 +00:00
def _format_vote(self, vote):
2019-06-17 16:51:42 +00:00
options = ["%d %s" % (len(v), k) for k, v in vote["options"].items()]
return "%s (%s)" % (vote["description"], ", ".join(options))
def _format_options(self, vote):
return ", ".join("'%s'" % o for o in vote["options"])
2019-06-17 15:36:48 +00:00
2019-06-17 16:51:42 +00:00
def _cast_vote(self, channel, vote_id, user, option):
vote = self._get_vote(channel, vote_id)
option = vote["options"][option]
voters = functools.reduce(operator.concat,
list(vote["options"].values()))
2019-06-17 15:29:14 +00:00
if user.name in voters:
return False
2019-06-17 16:51:42 +00:00
option.append(user.name)
self._set_vote(channel, vote_id, vote)
2019-06-17 15:29:14 +00:00
return True
2019-06-17 16:51:42 +00:00
def _open_votes(self, channel):
open = []
for setting, vote in channel.find_settings_prefix("vote-"):
if vote["open"]:
open.append(vote)
return open
2019-06-17 15:29:14 +00:00
@utils.hook("received.command.startvote", channel_only=True, min_args=1)
def start_vote(self, event):
"""
:help: Start a yes/no vote
:usage: <description>
:require_mode: o
2019-06-17 15:30:23 +00:00
:permission: vote
2019-06-17 15:29:14 +00:00
"""
2019-06-17 16:51:42 +00:00
vote = self._start_vote(event["target"], event["args"])
2019-06-17 15:29:14 +00:00
event["stdout"].write(
2019-06-17 16:51:42 +00:00
"Vote %s started. use '%svote <option>' to vote (options: %s)" %
(vote["id"], event["command_prefix"], self._format_options(vote)))
2019-06-17 15:29:14 +00:00
2019-06-17 16:51:42 +00:00
@utils.hook("received.command.endvote", channel_only=True, min_args=1)
2019-06-17 15:29:14 +00:00
def end_vote(self, event):
"""
:help: End the current yes/no vote
2019-06-17 16:51:42 +00:00
:usage: <id>
2019-06-17 15:29:14 +00:00
:require_mode: o
2019-06-17 15:30:23 +00:00
:permission: vote
2019-06-17 15:29:14 +00:00
"""
2019-06-17 16:51:42 +00:00
vote_id = event["args_split"][0]
if self._close_vote(event["target"], vote_id):
vote = self._get_vote(event["target"], vote_id)
2019-06-17 15:36:48 +00:00
event["stdout"].write("Vote %s ended: %s" %
(vote_id, self._format_vote(vote)))
2019-06-17 16:51:42 +00:00
else:
event["stderr"].write(STR_NOVOTE % vote_id)
2019-06-17 15:29:14 +00:00
2019-06-17 16:51:42 +00:00
@utils.hook("received.command.vote", channel_only=True, min_args=1)
2019-06-17 15:29:14 +00:00
def vote(self, event):
"""
:help: Vote in the channel's current vote
2019-06-17 16:51:42 +00:00
:usage: <id> yes|no
2019-06-17 15:29:14 +00:00
"""
2019-06-17 16:51:42 +00:00
vote_id = event["args_split"][0]
vote = self._get_vote(event["target"], vote_id)
2019-06-17 15:29:14 +00:00
if vote == None:
2019-06-17 16:51:42 +00:00
raise utils.EventError(STR_NOVOTE % vote_id)
2019-06-17 15:29:14 +00:00
2019-06-17 16:51:42 +00:00
if not len(event["args_split"]) > 1:
closed = "" if vote["open"] else " (closed)"
event["stdout"].write("Vote %s%s: %s" % (
vote_id, closed, self._format_vote(vote)))
2019-06-17 15:29:14 +00:00
else:
2019-06-17 16:51:42 +00:00
choice = event["args_split"][1].lower()
if not choice in vote["options"]:
raise utils.EventError("Vote options: %s" %
self._format_options(vote))
2019-06-17 15:29:14 +00:00
2019-06-17 16:51:42 +00:00
if self._cast_vote(event["target"], vote_id, event["user"], choice):
2019-06-17 15:29:14 +00:00
event["stdout"].write("%s: your vote has been cast." %
event["user"].nickname)
else:
event["stderr"].write("%s: you have already voted." %
event["user"].nickname)
2019-06-17 15:36:48 +00:00
2019-06-17 16:51:42 +00:00
@utils.hook("received.command.votes", channel_only=True)
def votes(self, event):
2019-06-17 15:36:48 +00:00
"""
2019-06-17 16:51:42 +00:00
:help: List open votes in the current channel
2019-06-17 15:36:48 +00:00
"""
2019-06-17 16:51:42 +00:00
open_votes = self._open_votes(event["target"])
if open_votes:
open_votes_str = [
"%s (%s)" % (v["description"], v["id"]) for v in open_votes]
event["stdout"].write("Open votes: %s" % ", ".join(open_votes_str))
2019-06-17 15:36:48 +00:00
else:
2019-06-17 16:51:42 +00:00
event["stderr"].write("There are no open votes")