Updates to Voteserv

- Add Admin override clause (enabled by config plugins.voteserv.allowadminoverride)
- Add listallvotes to list entire voting dictionary
- Add --hosts and --number options to 'votes' to list hostnames and only numbers
This commit is contained in:
James Lu 2014-11-19 18:01:23 -08:00
parent 09d3a4b5f6
commit 1009856b1f
3 changed files with 65 additions and 22 deletions

View File

@ -48,9 +48,11 @@ def configure(advanced):
Voteserv = conf.registerPlugin('Voteserv') Voteserv = conf.registerPlugin('Voteserv')
# This is where your configuration variables (if any) should go. For example: conf.registerGlobalValue(Voteserv, 'allowAdminOverride',
# conf.registerGlobalValue(Voteserv, 'someConfigVariableName', registry.Boolean(False, _("""Determines whether bot admins will be
# registry.Boolean(False, _("""Help for someConfigVariableName."""))) allowed to override duplicate vote checks.""")))
conf.registerGlobalValue(Voteserv, 'allowCheat',
registry.Boolean(False, _("""Determines whether the 'cheat' command
is enabled.""")))
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: # vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:

View File

@ -34,6 +34,7 @@ import supybot.utils as utils
from supybot.commands import * from supybot.commands import *
import supybot.plugins as plugins import supybot.plugins as plugins
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.ircdb as ircdb
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
try: try:
from supybot.i18n import PluginInternationalization from supybot.i18n import PluginInternationalization
@ -47,6 +48,10 @@ class Voteserv(callbacks.Plugin):
"""Small plugin for storing and manipulating votes/polls.""" """Small plugin for storing and manipulating votes/polls."""
threaded = True threaded = True
def _pluralize(self, n):
"""Returns 's' if <n> is not 1."""
return 's' if n != 1 else ''
def __init__(self, irc): def __init__(self, irc):
self.__parent = super(Voteserv, self) self.__parent = super(Voteserv, self)
self.__parent.__init__(irc) self.__parent.__init__(irc)
@ -99,10 +104,12 @@ class Voteserv(callbacks.Plugin):
Votes for something. It doesn't actually perform any actions directly, Votes for something. It doesn't actually perform any actions directly,
but could be an interesting way to get user feedback.""" but could be an interesting way to get user feedback."""
action = ircutils.stripFormatting(action.lower()).strip() action = ircutils.stripFormatting(action.lower()).strip()
override = self.registryValue("allowAdminOverride") and \
ircdb.checkCapability(msg.prefix, 'admin')
if not action: # It must be just whitespace or formatting codes if not action: # It must be just whitespace or formatting codes
irc.error("You must specify a proper action!", Raise=True) irc.error("You must specify a proper action!", Raise=True)
try: try:
if self._lazyhostmask(msg.prefix) in self.votedb[action]: if self._lazyhostmask(msg.prefix) in self.votedb[action] and not override:
irc.error("You have already voted to %s." % action, Raise=True) irc.error("You have already voted to %s." % action, Raise=True)
except KeyError: except KeyError:
self.votedb[action] = [0] self.votedb[action] = [0]
@ -113,9 +120,9 @@ class Voteserv(callbacks.Plugin):
def voteexport(self, irc, msg, args): def voteexport(self, irc, msg, args):
"""takes no arguments. """takes no arguments.
Exports votes stored in memory to file: data/votes.db Exports votes stored in memory to file: data/votes.db
This is also done automatically when the plugin is unloaded or This is also done automatically when the plugin is unloaded or
reloaded.""" reloaded."""
try: try:
self.exportVoteDB() self.exportVoteDB()
@ -127,7 +134,7 @@ class Voteserv(callbacks.Plugin):
def voteimport(self, irc, msg, args): def voteimport(self, irc, msg, args):
"""takes no arguments. """takes no arguments.
Imports the vote database for the current network.""" Imports the vote database for the current network."""
try: try:
self.loadVoteDB() self.loadVoteDB()
@ -139,38 +146,48 @@ class Voteserv(callbacks.Plugin):
def voteclear(self, irc, msg, args): def voteclear(self, irc, msg, args):
"""takes no arguments. """takes no arguments.
Clears all votes stored in memory. Use with caution!""" Clears all votes stored in memory. Use with caution!"""
self.votedb = {} self.votedb = {}
irc.replySuccess() irc.replySuccess()
voteclear = wrap(voteclear, ['admin']) voteclear = wrap(voteclear, ['admin'])
def votes(self, irc, msg, args, action): def votes(self, irc, msg, args, opts, action):
"""<action> """[--hosts] [--number] <action>
Returns the amount of people that have voted for <action>.""" Returns the amount of people that have voted for <action>. If
--hosts is given, also show the hosts that have voted for <action>.
If --number is given, only returns the number of people who has
voted for <action> (useful for nested commands)."""
action = ircutils.stripFormatting(action.lower()).strip() action = ircutils.stripFormatting(action.lower()).strip()
if not action: if not action:
irc.error("You must specify a proper action!", Raise=True) irc.error("You must specify a proper action!", Raise=True)
try: try:
n = self.votedb[action][0] n, hosts = self.votedb[action][0], self.votedb[action][1:]
except KeyError: except KeyError:
n = 0 n, hosts = 0, None
if irc.nested: opts = dict(opts)
if 'number' in opts:
irc.reply(n) irc.reply(n)
else: else:
irc.reply('\x02%s\x02 %s voted to %s' % s = '\x02%s\x02 %s voted to %s' % \
(n, 'person has' if n == 1 else 'people have', (n, 'person has' if n == 1 else 'people have', \
self._formatAction(action))) self._formatAction(action))
votes = wrap(votes, ['text']) if 'hosts' in opts and n:
s += " (%s)" % ", ".join(set(hosts))
irc.reply(s)
votes = wrap(votes, [getopts({'hosts':'', 'number':''}), 'text'])
def cheat(self, irc, msg, args, num, action): def cheat(self, irc, msg, args, num, action):
"""<number of votes> <action> """<number of votes> <action>
Sets the number of votes for <action> to a certain amount, Sets the number of votes for <action> to a certain amount,
perfect for rigged elections! perfect for rigged elections!
This will also reset the list of hosts that have voted for This will also reset the list of hosts that have voted for
<action>, allowing everyone to vote again.""" <action>, allowing everyone to vote again."""
if not self.registryValue("allowCheat"):
irc.error("This command is disabled; please set config plugins."
"voteserv.allowCheat accordingly.", Raise=True)
action = ircutils.stripFormatting(action.lower()).strip() action = ircutils.stripFormatting(action.lower()).strip()
if not action: if not action:
irc.error("You must specify a proper action!", Raise=True) irc.error("You must specify a proper action!", Raise=True)
@ -178,6 +195,16 @@ class Voteserv(callbacks.Plugin):
irc.replySuccess() irc.replySuccess()
cheat = wrap(cheat, ['admin', 'int', 'text']) cheat = wrap(cheat, ['admin', 'int', 'text'])
def listallvotes(self, irc, msg, args):
"""<takes no arguments>.
Returns the list of things that have been voted for, along
with the number of votes for each."""
s = "; ".join(['"%s": \x02%s\x02 vote%s' % (k, v[0], self._pluralize(v[0]))
for k, v in self.votedb.items()])
irc.reply(s)
listallvotes = wrap(listallvotes)
Class = Voteserv Class = Voteserv

View File

@ -31,7 +31,8 @@
from supybot.test import * from supybot.test import *
class VoteservTestCase(PluginTestCase): class VoteservTestCase(PluginTestCase):
plugins = ('Voteserv',) plugins = ('Voteserv','Admin')
config = {'supybot.plugins.voteserv.allowCheat': True}
def setUp(self): def setUp(self):
PluginTestCase.setUp(self) PluginTestCase.setUp(self)
@ -67,4 +68,17 @@ class VoteservTestCase(PluginTestCase):
self.assertError('cheat 30 " "') self.assertError('cheat 30 " "')
self.assertNotError('cheat 30 " lose the game\x02 "') self.assertNotError('cheat 30 " lose the game\x02 "')
self.assertRegexp('votes lose the game ', ".*?30.*?voted to.*?") self.assertRegexp('votes lose the game ', ".*?30.*?voted to.*?")
def testAdminOverride(self):
conf.supybot.plugins.voteserv.allowAdminOverride.setValue(True)
try:
u = ircdb.users.newUser()
u.name = 'abcde'
ircdb.users.setUser(u)
self.assertNotError('capability add abcde admin')
self.assertNotError('vote test something')
self.assertNotError('vote test something')
finally:
conf.supybot.plugins.voteserv.allowAdminOverride.setValue(False)
ircdb.users.delUser(u.id)
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: # vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: