Fixed tests, and changed to use invalidCommand rather than addressedRegexps so commands may now be nested in definitions.

This commit is contained in:
Jeremy Fincher 2004-09-12 20:24:08 +00:00
parent 39f427d4be
commit 4f9e67a796
2 changed files with 227 additions and 264 deletions

View File

@ -30,10 +30,9 @@
### ###
""" """
Moobot factoid compatibility module. Overrides the replyWhenNotCommand Moobot factoid compatibility module. Moobot's factoids were originally
behavior so that when someone addresses the bot with anything other than a designed to emulate Blootbot's factoids, so in either case, you should find
command, it checks the factoid database for a key that matches what was said this plugin comfortable.
and if nothing is found, responds with an entry from the "dunno" database.
""" """
import supybot import supybot
@ -64,12 +63,6 @@ import supybot.callbacks as callbacks
import supybot.Owner as Owner import supybot.Owner as Owner
try:
import sqlite
except ImportError:
raise callbacks.Error, 'You need to have PySQLite installed to use this ' \
'plugin. Download it at <http://pysqlite.sf.net/>'
allchars = string.maketrans('', '') allchars = string.maketrans('', '')
class OptionList(object): class OptionList(object):
validChars = allchars.translate(allchars, '|()') validChars = allchars.translate(allchars, '|()')
@ -130,8 +123,16 @@ conf.registerChannelValue(conf.supybot.plugins.MoobotFactoids,
when the 'most' command is called.""")) when the 'most' command is called."""))
class SqliteMoobotDB(object): class SqliteMoobotDB(object):
def __init__(self, filename):
self.filename = filename
def _getDb(self, channel): def _getDb(self, channel):
filename = plugins.makeChannelFilename(channel, 'MoobotFactoids.db') try:
import sqlite
except ImportError:
raise callbacks.Error, \
'You need to have PySQLite installed to use this ' \
'plugin. Download it at <http://pysqlite.sf.net/>'
filename = plugins.makeChannelFilename(self.filename, channel)
if os.path.exists(filename): if os.path.exists(filename):
db = sqlite.connect(filename) db = sqlite.connect(filename)
else: else:
@ -276,11 +277,11 @@ class SqliteMoobotDB(object):
else: else:
return cursor.fetchall() return cursor.fetchall()
def getKeysByAuthor(self, channel, author_id): def getKeysByAuthor(self, channel, authorId):
db = self._getDb(channel) db = self._getDb(channel)
cursor = db.cursor() cursor = db.cursor()
cursor.execute("""SELECT key FROM factoids WHERE created_by=%s cursor.execute("""SELECT key FROM factoids WHERE created_by=%s
ORDER BY key""", author_id) ORDER BY key""", authorId)
if cursor.rowcount == 0: if cursor.rowcount == 0:
return None return None
else: else:
@ -306,218 +307,182 @@ class SqliteMoobotDB(object):
else: else:
return cursor.fetchall() return cursor.fetchall()
def MoobotDB(): MoobotDB = plugins.DB('MoobotFactoids', {'sqlite': SqliteMoobotDB})
return SqliteMoobotDB()
class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp): # We define our own getChannel so we can set raiseError=False in one place.
def getChannel(msg, args=()):
return privmsgs.getChannel(msg, args, raiseError=False)
class MoobotFactoids(callbacks.Privmsg):
callBefore = ['Dunno'] callBefore = ['Dunno']
addressedRegexps = ['changeFactoid', 'augmentFactoid',
'replaceFactoid', 'addFactoid']
def __init__(self): def __init__(self):
self.db = MoobotDB() self.db = MoobotDB()
callbacks.PrivmsgCommandAndRegexp.__init__(self) super(MoobotFactoids, self).__init__()
_replyTag = '<reply>'
_actionTag = '<action>'
def _parseFactoid(self, irc, msg, fact): def _parseFactoid(self, irc, msg, fact):
type = "define" # Default is to just spit the factoid back as a type = 'define' # Default is to just spit the factoid back as a
# definition of what the key is (i.e., "foo is bar") # definition of what the key is (i.e., "foo is bar")
newfact = pickOptions(fact) newfact = pickOptions(fact)
if newfact.startswith("<reply>"): if newfact.startswith(self._replyTag):
newfact = newfact[7:] newfact = newfact[len(self._replyTag):]
type = "reply" type = 'reply'
elif newfact.startswith("<action>"): elif newfact.startswith(self._actionTag):
newfact = newfact[8:] newfact = newfact[len(self._actionTag):]
type = "action" type = 'action'
newfact = newfact.strip() newfact = newfact.strip()
newfact = plugins.standardSubstitute(irc, msg, newfact) newfact = plugins.standardSubstitute(irc, msg, newfact)
return (type, newfact) return (type, newfact)
def randomfactoid(self, irc, msg, args):
"""takes no arguments
Displays a random factoid (along with its key) from the database.
"""
channel = privmsgs.getChannel(msg, args)
tup = self.db.randomFactoid(channel)
if tup is None:
irc.error('No factoids in the database.')
else:
irc.reply('"%s" is "%s"' % tup)
def invalidCommand(self, irc, msg, tokens): def invalidCommand(self, irc, msg, tokens):
key = ' '.join(tokens) if '=~' in tokens:
key = key.rstrip('?!') self.changeFactoid(irc, msg, tokens)
channel = privmsgs.getChannel(msg, list(msg.args)) elif tokens and tokens[0] in ('no', 'no,'):
# ignore ACTIONs self.replaceFactoid(irc, msg, tokens)
if key.startswith('\x01'): elif ['is', 'also'] in window(tokens, 2):
return self.augmentFactoid(irc, msg, tokens)
# Check the factoid db for an appropriate reply
fact = self.db.getFactoid(channel, key)
if not fact:
return False
else: else:
key = ' '.join(tokens)
key = self._sanitizeKey(key)
channel = getChannel(msg)
fact = self.db.getFactoid(channel, key)
if fact:
self.db.updateRequest(channel, key, msg.prefix)
# getFactoid returns "all results", so we need to extract the # getFactoid returns "all results", so we need to extract the
# first one # first one.
fact = fact[0] fact = fact[0]
# Update the requested count/requested by for this key # Update the requested count/requested by for this key
hostmask = msg.prefix hostmask = msg.prefix
self.db.updateRequest(channel, key, hostmask)
# Now actually get the factoid and respond accordingly # Now actually get the factoid and respond accordingly
(type, text) = self._parseFactoid(irc, msg, fact) (type, text) = self._parseFactoid(irc, msg, fact)
if type == "action": if type == 'action':
irc.reply(text, action=True) irc.reply(text, action=True)
elif type == "reply": elif type == 'reply':
irc.reply(text, prefixName=False) irc.reply(text, prefixName=False)
elif type == "define": elif type == 'define':
irc.reply("%s is %s" % (key, text), prefixName=False) irc.reply('%s is %s' % (key, text), prefixName=False)
else: else:
irc.error("Spurious type from _parseFactoid.") assert False, 'Spurious type from _parseFactoid'
return True else:
if 'is' in tokens or '_is_' in tokens:
self.addFactoid(irc, msg, tokens)
# XXX It looks like all these could be converted to use invalidCommand def _getUserId(self, prefix):
# instead, which would then also allow nested commands. Strike may want try:
# to consider that implementation method. return ircdb.users.getUserId(prefix)
def addFactoid(self, irc, msg, match): except KeyError:
irc.errorNotRegistered(Raise=True)
def _sanitizeKey(self, key):
return key.rstrip('!? ')
def _checkNotLocked(self, irc, channel, key):
if self.db.locked(channel, key):
irc.error('Factoid "%s" is locked.' % key, Raise=True)
def _getFactoid(self, channel, key):
fact = self.db.getFactoid(channel, key)
if fact is not None:
return fact
else:
irc.error('Factoid "%s" not found.' % key, Raise=True)
def _getKeyAndFactoid(self, tokens):
if '_is_' in tokens:
p = '_is_'.__eq__
elif 'is' in tokens:
p = 'is'.__eq__
else:
s = 'Invalid tokens for {add,change}Factoid: %r' % tokens
raise ValueError, s
(key, newfact) = map(' '.join, utils.itersplit(p, tokens, maxsplit=1))
key = self._sanitizeKey(key)
return (key, newfact)
def addFactoid(self, irc, msg, tokens):
r"^(?!\x01)(.+?)\s+(?:is|_is_)\s+(.+)" r"^(?!\x01)(.+?)\s+(?:is|_is_)\s+(.+)"
# First, check and see if the entire message matches a factoid key # First, check and see if the entire message matches a factoid key
channel = privmsgs.getChannel(msg, list(msg.args)) channel = getChannel(msg)
key = match.group().rstrip('?! ') id = self._getUserId(msg.prefix)
fact = self.db.getFactoid(channel, key) (key, fact) = self._getKeyAndFactoid(tokens)
# If it exists, call invalidCommand to display it
if fact:
self.invalidCommand(irc, msg, callbacks.tokenize(match.group()))
return
# Okay, we are REALLY adding stuff
# Must be registered!
try:
id = ircdb.users.getUserId(msg.prefix)
except KeyError:
irc.errorNotRegistered()
return
key, newfact = match.groups()
# These are okay, unless there's an _is_ in there, in which case
# we split on the leftmost one.
if '_is_' in match.group():
key, newfact = imap(str.strip, match.group().split('_is_', 1))
# Strip the key of punctuation and spaces
key = key.rstrip('?! ')
# Check and make sure it's not in the DB already # Check and make sure it's not in the DB already
fact = self.db.getFactoid(channel, key) if self.db.getFactoid(channel, key):
if fact: irc.error('Factoid "%s" already exists.' % key, Raise=True)
irc.error('Factoid "%s" already exists.' % key) self.db.addFactoid(channel, key, fact, id)
return
# Otherwise,
self.db.addFactoid(channel, key, newfact, id)
irc.replySuccess() irc.replySuccess()
def changeFactoid(self, irc, msg, match): def changeFactoid(self, irc, msg, tokens):
r"(.+)\s+=~\s+(.+)" r"(.+)\s+=~\s+(.+)"
# Must be registered! id = self._getUserId(msg.prefix)
try: (key, regexp) = map(' '.join,
id = ircdb.users.getUserId(msg.prefix) utils.itersplit('=~'.__eq__, tokens, maxsplit=1))
except KeyError: channel = getChannel(msg)
irc.errorNotRegistered()
return
key, regexp = match.groups()
channel = privmsgs.getChannel(msg, list(msg.args))
# Check and make sure it's in the DB # Check and make sure it's in the DB
fact = self.db.getFactoid(channel, key) fact = self._getFactoid(channel, key)
if not fact: self._checkNotLocked(irc, channel, key)
irc.error('Factoid "%s" not found.' % key)
return
# No dice if it's locked, no matter who it is
locked = self.db.locked(channel, key)
if locked:
irc.error('Factoid "%s" is locked.' % key)
return
# It's fair game if we get to here # It's fair game if we get to here
try: try:
r = utils.perlReToReplacer(regexp) r = utils.perlReToReplacer(regexp)
except ValueError, e: except ValueError, e:
irc.error('Invalid regexp: "%s"' % regexp) irc.errorInvalid('regexp', regexp, Raise=True)
return
fact = fact[0] fact = fact[0]
new_fact = r(fact) new_fact = r(fact)
self.db.updateFactoid(channel, key, new_fact, id) self.db.updateFactoid(channel, key, new_fact, id)
irc.replySuccess() irc.replySuccess()
def augmentFactoid(self, irc, msg, match): def augmentFactoid(self, irc, msg, tokens):
r"(.+?) is also (.+)" r"(.+?) is also (.+)"
# Must be registered! # Must be registered!
try: id = self._getUserId(msg.prefix)
id = ircdb.users.getUserId(msg.prefix) pairs = list(window(tokens, 2))
except KeyError: isAlso = pairs.index(['is', 'also'])
irc.errorNotRegistered() key = ' '.join(tokens[:isAlso])
return new_text = ' '.join(tokens[isAlso+2:])
key, new_text = match.groups() channel = getChannel(msg)
channel = privmsgs.getChannel(msg, list(msg.args)) fact = self._getFactoid(channel, key)
fact = self.db.getFactoid(channel, key) self._checkNotLocked(irc, channel, key)
# Check and make sure it's in the DB
if not fact:
irc.error('Factoid "%s" not found.' % key)
return
# No dice if it's locked, no matter who it is
locked = self.db.locked(channel, key)
if locked:
irc.error('Factoid "%s" is locked.' % key)
return
# It's fair game if we get to here # It's fair game if we get to here
fact = fact[0] fact = fact[0]
new_fact = "%s, or %s" % (fact, new_text) new_fact = "%s, or %s" % (fact, new_text)
self.db.updateFactoid(channel, key, new_fact, id) self.db.updateFactoid(channel, key, new_fact, id)
irc.replySuccess() irc.replySuccess()
def replaceFactoid(self, irc, msg, match): def replaceFactoid(self, irc, msg, tokens):
r"^no,?\s+(.+?)\s+is\s+(.+)" r"^no,?\s+(.+?)\s+is\s+(.+)"
# Must be registered! # Must be registered!
try: channel = getChannel(msg)
id = ircdb.users.getUserId(msg.prefix) id = self._getUserId(msg.prefix)
except KeyError: del tokens[0] # remove the "no,"
irc.errorNotRegistered() (key, fact) = self._getKeyAndFactoid(tokens)
return _ = self._getFactoid(channel, key) # Complains if not already in db.
key, new_fact = match.groups() self._checkNotLocked(irc, channel, key)
# These are okay, unless there's an _is_ in there, in which case
# we split on the leftmost one.
if '_is_' in match.group():
key, new_fact = imap(str.strip, match.group().split('_is_', 1))
key = key.split(' ', 1)[1] # Take out everything to first space
# Check and make sure it's in the DB
channel = privmsgs.getChannel(msg, list(msg.args))
fact = self.db.getFactoid(channel, key)
if not fact:
irc.error('Factoid "%s" not found.' % key)
return
# No dice if it's locked, no matter who it is
locked = self.db.locked(channel, key)
if locked:
irc.error('Factoid "%s" is locked.' % key)
return
# It's fair game if we get to here
self.db.removeFactoid(channel, key) self.db.removeFactoid(channel, key)
self.db.addFactoid(channel, key, new_fact, id) self.db.addFactoid(channel, key, fact, id)
irc.replySuccess() irc.replySuccess()
def literal(self, irc, msg, args): def literal(self, irc, msg, args):
"""<factoid key> """[<channel>] <factoid key>
Returns the literal factoid for the given factoid key. No parsing of Returns the literal factoid for the given factoid key. No parsing of
the factoid value is done as it is with normal retrieval. the factoid value is done as it is with normal retrieval. <channel>
is only necessary if the message isn't sent in the channel itself.
""" """
channel = privmsgs.getChannel(msg, args) channel = getChannel(msg, args)
key = privmsgs.getArgs(args, required=1) key = privmsgs.getArgs(args)
fact = self.db.getFactoid(channel, key) fact = self._getFactoid(channel, key)
if not fact:
irc.error('No such factoid: "%s"' % key)
else:
fact = fact[0] fact = fact[0]
irc.reply(fact) irc.reply(fact)
def factinfo(self, irc, msg, args): def factinfo(self, irc, msg, args):
"""<factoid key> """[<channel>] <factoid key>
Returns the various bits of info on the factoid for the given key. Returns the various bits of info on the factoid for the given key.
<channel> is only necessary if the message isn't sent in the channel
itself.
""" """
channel = privmsgs.getChannel(msg, args) channel = getChannel(msg, args)
key = privmsgs.getArgs(args, required=1) key = privmsgs.getArgs(args)
# Start building the response string # Start building the response string
s = key + ": " s = key + ": "
# Next, get all the info and build the response piece by piece # Next, get all the info and build the response piece by piece
@ -564,8 +529,8 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
irc.errorNotRegistered() irc.errorNotRegistered()
return return
self.log.debug('id: %s' % id) self.log.debug('id: %s' % id)
channel = privmsgs.getChannel(msg, args) channel = getChannel(msg, args)
key = privmsgs.getArgs(args, required=1) key = privmsgs.getArgs(args)
info = self.db.getFactinfo(channel, key) info = self.db.getFactinfo(channel, key)
if not info: if not info:
irc.error('No such factoid: "%s"' % key) irc.error('No such factoid: "%s"' % key)
@ -597,95 +562,103 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
irc.replySuccess() irc.replySuccess()
def lock(self, irc, msg, args): def lock(self, irc, msg, args):
"""<factoid key> """[<channel>] <factoid key>
Locks the factoid with the given factoid key. Requires that the user Locks the factoid with the given factoid key. Requires that the user
be registered and have created the factoid originally. be registered and have created the factoid originally. <channel> is
only necessary if the message isn't sent in the channel itself.
""" """
self._lock(irc, msg, args, True) self._lock(irc, msg, args, True)
def unlock(self, irc, msg, args): def unlock(self, irc, msg, args):
"""<factoid key> """[<channel>] <factoid key>
Unlocks the factoid with the given factoid key. Requires that the Unlocks the factoid with the given factoid key. Requires that the
user be registered and have locked the factoid. user be registered and have locked the factoid. <channel> is only
necessary if the message isn't sent in the channel itself.
""" """
self._lock(irc, msg, args, False) self._lock(irc, msg, args, False)
class MostException(Exception):
pass
def most(self, irc, msg, args): def most(self, irc, msg, args):
"""<popular|authored|recent> """[<channel>] {popular|authored|recent}
Lists the most <popular|authored|recent> factoids. <popular> lists the Lists the most {popular|authored|recent} factoids. "popular" lists the
most frequently requested factoids. <authored> lists the author with most frequently requested factoids. "authored" lists the author with
the most factoids. <recent> lists the most recently created factoids. the most factoids. "recent" lists the most recently created factoids.
<channel> is only necessary if the message isn't sent in the channel
itself.
""" """
channel = privmsgs.getChannel(msg, args) channel = getChannel(msg, args)
arg = privmsgs.getArgs(args) arg = privmsgs.getArgs(args)
arg = arg.capitalize() arg = arg.capitalize()
method = getattr(self, '_most%s' % arg, None) method = getattr(self, '_most%s' % arg, None)
if method is None: if method is None:
raise callbacks.ArgumentError raise callbacks.ArgumentError
limit = self.registryValue('mostCount', channel) limit = self.registryValue('mostCount', channel)
irc.reply(method(channel, limit)) method(irc, channel, limit)
def _mostAuthored(self, channel, limit): def _mostAuthored(self, irc, channel, limit):
results = self.db.mostAuthored(channel, limit) results = self.db.mostAuthored(channel, limit)
L = ['%s (%s)' % (ircdb.users.getUser(t[0]).name, int(t[1])) L = ['%s (%s)' % (ircdb.users.getUser(t[0]).name, int(t[1]))
for t in results] for t in results]
return 'Most prolific %s: %s' % \ if L:
(utils.pluralize('author', len(L)), utils.commaAndify(L)) irc.reply('Most prolific %s: %s' %
(utils.pluralize('author', len(L)),utils.commaAndify(L)))
else:
irc.error('There are no factoids in my database.')
def _mostRecent(self, channel, limit): def _mostRecent(self, irc, channel, limit):
results = self.db.mostRecent(channel, limit) results = self.db.mostRecent(channel, limit)
L = ['"%s"' % t[0] for t in results] L = ['"%s"' % t[0] for t in results]
return '%s: %s' % \ if L:
irc.reply('%s: %s' %
(utils.nItems('factoid', len(L), between='latest'), (utils.nItems('factoid', len(L), between='latest'),
utils.commaAndify(L)) utils.commaAndify(L)))
else:
irc.error('There are no factoids in my database.')
def _mostPopular(self, channel, limit): def _mostPopular(self, irc, channel, limit):
results = self.db.mostPopular(channel, limit) results = self.db.mostPopular(channel, limit)
if not results:
raise self.MostException, 'No factoids have been requested.'
L = ['"%s" (%s)' % (t[0], t[1]) for t in results] L = ['"%s" (%s)' % (t[0], t[1]) for t in results]
return 'Top %s: %s' % \ if L:
irc.reply('Top %s: %s' %
(utils.nItems('factoid', len(L), between='requested'), (utils.nItems('factoid', len(L), between='requested'),
utils.commaAndify(L)) utils.commaAndify(L)))
else:
irc.error('No factoids have been requested from my database.')
def listauth(self, irc, msg, args): def listauth(self, irc, msg, args):
"""<author name> """[<channel>] <author name>
Lists the keys of the factoids with the given author. Note that if an Lists the keys of the factoids with the given author. Note that if an
author has an integer name, you'll have to use that author's id to use author has an integer name, you'll have to use that author's id to use
this function (so don't use integer usernames!). this function (so don't use integer usernames!). <channel> is only
necessary if the message isn't sent in the channel itself.
""" """
channel = privmsgs.getChannel(msg, args) channel = getChannel(msg, args)
author = privmsgs.getArgs(args, required=1) author = privmsgs.getArgs(args)
try: try:
id = ircdb.users.getUserId(author) id = ircdb.users.getUserId(author)
except KeyError: except KeyError:
irc.error("No such user: %r" % author) irc.errorNoUser(name=author, Raise=True)
return
results = self.db.getKeysByAuthor(channel, id) results = self.db.getKeysByAuthor(channel, id)
if not results: if not results:
irc.reply('No factoids by "%s" found.' % author) irc.reply('No factoids by "%s" found.' % author)
return return
keys = ['"%s"' % tup[0] for tup in results] keys = ['"%s"' % t[0] for t in results]
s = 'Author search for "%s" (%s found): %s' % \ s = 'Author search for "%s" (%s found): %s' % \
(author, len(keys), utils.commaAndify(keys)) (author, len(keys), utils.commaAndify(keys))
irc.reply(s) irc.reply(s)
def listkeys(self, irc, msg, args): def listkeys(self, irc, msg, args):
"""<text> """[<channel>] <text>
Lists the keys of the factoids whose key contains the provided text. Lists the keys of the factoids whose key contains the provided text.
<channel> is only necessary if the message isn't sent in the channel
itself.
""" """
channel = privmsgs.getChannel(msg, args) channel = getChannel(msg, args)
search = privmsgs.getArgs(args, required=1) search = privmsgs.getArgs(args)
# Don't error if we aren't in a channel, private messages are okay
channel = privmsgs.getChannel(msg, args, raiseError=False)
glob = '%' + search + '%' glob = '%' + search + '%'
results = self.db.getKeysByGlob(channel, glob) results = self.db.getKeysByGlob(channel, glob)
if not results: if not results:
@ -701,12 +674,14 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
irc.reply(s) irc.reply(s)
def listvalues(self, irc, msg, args): def listvalues(self, irc, msg, args):
"""<text> """[<channel>] <text>
Lists the keys of the factoids whose value contains the provided text. Lists the keys of the factoids whose value contains the provided text.
<channel> is only necessary if the message isn't sent in the channel
itself.
""" """
channel = privmsgs.getChannel(msg, args) channel = getChannel(msg, args)
search = privmsgs.getArgs(args, required=1) search = privmsgs.getArgs(args)
glob = '%' + search + '%' glob = '%' + search + '%'
results = self.db.getKeysByValueGlob(channel, glob) results = self.db.getKeysByValueGlob(channel, glob)
if not results: if not results:
@ -718,35 +693,28 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
irc.reply(s) irc.reply(s)
def delete(self, irc, msg, args): def delete(self, irc, msg, args):
"""<factoid key> """[<channel>] <factoid key>
Deletes the factoid with the given key. Deletes the factoid with the given key. <channel> is only necessary
if the message isn't sent in the channel itself.
""" """
# Must be registered to use this channel = getChannel(msg, args)
try: key = privmsgs.getArgs(args)
ircdb.users.getUserId(msg.prefix) _ = self._getUserId(msg.prefix)
except KeyError: _ = self._getFactoid(channel, key)
irc.errorNotRegistered() self._checkNotLocked(irc, channel, key)
return
channel = privmsgs.getChannel(msg, args)
key = privmsgs.getArgs(args, required=1)
fact = self.db.getFactoid(channel, key)
if not fact:
irc.error('No such factoid: "%s"' % key)
return
locked = self.db.locked(channel, key)
if locked:
irc.error("Factoid is locked, cannot remove.")
return
self.db.removeFactoid(channel, key) self.db.removeFactoid(channel, key)
irc.replySuccess() irc.replySuccess()
# XXX What the heck? Why are there two definitions of randomfactoid?
def randomfactoid(self, irc, msg, args): def randomfactoid(self, irc, msg, args):
"""takes no arguments """[<channel>]
Displays a random factoid (along with its key) from the database. Displays a random factoid (along with its key) from the database.
<channel> is only necessary if the message isn't sent in the channel
itself.
""" """
channel = privmsgs.getChannel(msg, args) channel = getChannel(msg, args)
results = self.db.randomFactoid(channel) results = self.db.randomFactoid(channel)
if not results: if not results:
irc.error('No factoids in the database.') irc.error('No factoids in the database.')

View File

@ -32,6 +32,8 @@
from testsupport import * from testsupport import *
import supybot.ircutils as ircutils
try: try:
import sqlite import sqlite
except ImportError: except ImportError:
@ -70,7 +72,7 @@ if sqlite is not None:
def setUp(self): def setUp(self):
ChannelPluginTestCase.setUp(self) ChannelPluginTestCase.setUp(self)
# Create a valid user to use # Create a valid user to use
self.prefix = 'foo!bar@baz' self.prefix = 'mf!bar@baz'
self.irc.feedMsg(ircmsgs.privmsg(self.nick, 'register tester moo', self.irc.feedMsg(ircmsgs.privmsg(self.nick, 'register tester moo',
prefix=self.prefix)) prefix=self.prefix))
m = self.irc.takeMsg() # Response to register. m = self.irc.takeMsg() # Response to register.
@ -85,9 +87,11 @@ if sqlite is not None:
self.assertResponse('bar', 'moo is moo') self.assertResponse('bar', 'moo is moo')
# Check substitution # Check substitution
self.assertNotError('who is <reply>$who') self.assertNotError('who is <reply>$who')
self.assertResponse('who', 'foo') self.assertResponse('who', ircutils.nickFromHostmask(self.prefix))
# Check that actions ("\x01ACTION...") don't match # Check that actions ("\x01ACTION...") don't match
self.assertNoResponse('\x01ACTION is doing something\x01', 3) m = ircmsgs.action(self.channel, 'is doing something')
self.irc.feedMsg(m)
self.assertNoResponse(' ', 1)
def testLiteral(self): def testLiteral(self):
self.assertError('literal moo') # no factoids yet self.assertError('literal moo') # no factoids yet
@ -123,34 +127,28 @@ if sqlite is not None:
self.assertNotError('moo is <reply>foo') self.assertNotError('moo is <reply>foo')
self.assertRegexp('factinfo moo', '^moo: Created by tester on.*$') self.assertRegexp('factinfo moo', '^moo: Created by tester on.*$')
self.assertNotError('moo') self.assertNotError('moo')
self.assertRegexp('factinfo moo', self.assertRegexp('factinfo moo', self.prefix + '.*1 time')
'^moo: Created by tester on'
'.*?\. Last requested by foo!bar@baz on .*?, '
'requested 1 time.$')
self.assertNotError('moo') self.assertNotError('moo')
self.assertRegexp('factinfo moo', self.assertRegexp('factinfo moo', self.prefix + '.*2 times')
'^moo: Created by tester on'
'.*?\. Last requested by foo!bar@baz on .*?, '
'requested 2 times.$')
self.assertNotError('moo =~ s/foo/bar/') self.assertNotError('moo =~ s/foo/bar/')
self.assertRegexp('factinfo moo', self.assertRegexp('factinfo moo',
'^moo: Created by tester on' '^moo: Created by tester on'
'.*?\. Last modified by tester on .*?\. ' '.*?\. Last modified by tester on .*?\. '
'Last requested by foo!bar@baz on .*?, ' 'Last requested by %s on .*?, '
'requested 2 times.$') 'requested 2 times.$' % self.prefix)
self.assertNotError('lock moo') self.assertNotError('lock moo')
self.assertRegexp('factinfo moo', self.assertRegexp('factinfo moo',
'^moo: Created by tester on' '^moo: Created by tester on'
'.*?\. Last modified by tester on .*?\. ' '.*?\. Last modified by tester on .*?\. '
'Last requested by foo!bar@baz on .*?, ' 'Last requested by %s on .*?, '
'requested 2 times. ' 'requested 2 times. '
'Locked by tester on .*\.$') 'Locked by tester on .*\.$' % self.prefix)
self.assertNotError('unlock moo') self.assertNotError('unlock moo')
self.assertRegexp('factinfo moo', self.assertRegexp('factinfo moo',
'^moo: Created by tester on' '^moo: Created by tester on'
'.*?\. Last modified by tester on .*?\. ' '.*?\. Last modified by tester on .*?\. '
'Last requested by foo!bar@baz on .*?, ' 'Last requested by %s on .*?, '
'requested 2 times.$') 'requested 2 times.$' % self.prefix)
# Make sure I solved this bug # Make sure I solved this bug
# Check and make sure all the other stuff is reset # Check and make sure all the other stuff is reset
self.assertNotError('foo is bar') self.assertNotError('foo is bar')
@ -172,15 +170,16 @@ if sqlite is not None:
'^moo: Created by tester on' '^moo: Created by tester on'
'.*?\. Locked by tester on .*?\.') '.*?\. Locked by tester on .*?\.')
# switch user # switch user
original = self.prefix
self.prefix = 'moo!moo@moo' self.prefix = 'moo!moo@moo'
self.assertNotError('register nottester moo') self.assertNotError('register nottester moo', private=True)
self.assertError('unlock moo') self.assertError('unlock moo')
self.assertRegexp('factinfo moo', self.assertRegexp('factinfo moo',
'^moo: Created by tester on' '^moo: Created by tester on'
'.*?\. Locked by tester on .*?\.') '.*?\. Locked by tester on .*?\.')
# switch back # switch back
self.prefix = 'foo!bar@baz' self.prefix = original
self.assertNotError('identify tester moo') self.assertNotError('identify tester moo', private=True)
self.assertNotError('unlock moo') self.assertNotError('unlock moo')
self.assertRegexp('factinfo moo', self.assertRegexp('factinfo moo',
'^moo: Created by tester on.*?\.') '^moo: Created by tester on.*?\.')
@ -200,14 +199,10 @@ if sqlite is not None:
def testMost(self): def testMost(self):
userPrefix1 = 'moo!bar@baz'; userNick1 = 'moo' userPrefix1 = 'moo!bar@baz'; userNick1 = 'moo'
userPrefix2 = 'boo!bar@baz'; userNick2 = 'boo' userPrefix2 = 'boo!bar@baz'; userNick2 = 'boo'
self.irc.feedMsg(ircmsgs.privmsg(self.irc.nick, self.assertNotError('register %s bar' % userNick1,
'register %s bar' % userNick1, frm=userPrefix1, private=True)
prefix=userPrefix1)) self.assertNotError('register %s bar' % userNick2,
self.irc.feedMsg(ircmsgs.privmsg(self.irc.nick, frm=userPrefix2, private=True)
'register %s bar' % userNick2,
prefix=userPrefix2))
_ = self.irc.takeMsg()
_ = self.irc.takeMsg()
# Check an empty database # Check an empty database
self.assertError('most popular') self.assertError('most popular')
self.assertError('most authored') self.assertError('most authored')