Spankin' new abstraction!

This commit is contained in:
Daniel DiPaolo 2004-09-05 17:29:22 +00:00
parent e271ea6a47
commit ebb7becd4f
1 changed files with 259 additions and 192 deletions

View File

@ -70,9 +70,6 @@ except ImportError:
raise callbacks.Error, 'You need to have PySQLite installed to use this ' \ raise callbacks.Error, 'You need to have PySQLite installed to use this ' \
'plugin. Download it at <http://pysqlite.sf.net/>' 'plugin. Download it at <http://pysqlite.sf.net/>'
dbfilename = os.path.join(conf.supybot.directories.data(), 'MoobotFactoids')
allchars = string.maketrans('', '') allchars = string.maketrans('', '')
class OptionList(object): class OptionList(object):
validChars = allchars.translate(allchars, '|()') validChars = allchars.translate(allchars, '|()')
@ -128,14 +125,17 @@ conf.registerChannelValue(conf.supybot.plugins.MoobotFactoids,
'showFactoidIfOnlyOneMatch', registry.Boolean(True, """Determines whether 'showFactoidIfOnlyOneMatch', registry.Boolean(True, """Determines whether
or not the factoid value will be shown when a listkeys search returns only or not the factoid value will be shown when a listkeys search returns only
one factoid key.""")) one factoid key."""))
conf.registerChannelValue(conf.supybot.plugins.MoobotFactoids,
'mostCount', registry.Integer(10, """Determines how many items are shown
when the 'most' command is called."""))
class MoobotDBHandler(plugins.DBHandler): class SqliteMoobotDB(object):
def makeDb(self, filename): def _getDb(self, channel):
"""create MoobotFactoids database and tables""" filename = plugins.makeChannelFilename(channel, 'MoobotFactoids.db')
if os.path.exists(filename): if os.path.exists(filename):
db = sqlite.connect(filename) db = sqlite.connect(filename)
else: else:
db = sqlite.connect(filename, converters={'bool': bool}) db = sqlite.connect(filename)
cursor = db.cursor() cursor = db.cursor()
cursor.execute("""CREATE TABLE factoids ( cursor.execute("""CREATE TABLE factoids (
key TEXT PRIMARY KEY, key TEXT PRIMARY KEY,
@ -153,18 +153,169 @@ class MoobotDBHandler(plugins.DBHandler):
db.commit() db.commit()
return db return db
def getFactoid(self, channel, key):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""SELECT fact FROM factoids
WHERE key LIKE %s""", key)
if cursor.rowcount == 0:
return None
else:
return cursor.fetchall()[0]
def getFactinfo(self, channel, key):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""SELECT created_by, created_at,
modified_by, modified_at,
last_requested_by, last_requested_at,
requested_count, locked_by, locked_at
FROM factoids
WHERE key LIKE %s""", key)
if cursor.rowcount == 0:
return None
else:
return cursor.fetchone()
def randomFactoid(self, channel):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""SELECT fact, key FROM factoids
ORDER BY random() LIMIT 1""")
if cursor.rowcount == 0:
return None
else:
return cursor.fetchone()
def addFactoid(self, channel, key, value, creator_id):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""INSERT INTO factoids VALUES
(%s, %s, %s, NULL, NULL, NULL, NULL,
NULL, NULL, %s, 0)""",
key, creator_id, int(time.time()), value)
db.commit()
def updateFactoid(self, channel, key, newvalue, modifier_id):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""UPDATE factoids
SET fact=%s, modified_by=%s,
modified_at=%s WHERE key LIKE %s""",
newvalue, modifier_id, int(time.time()), key)
db.commit()
def updateRequest(self, channel, key, hostmask):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""UPDATE factoids SET
last_requested_by = %s,
last_requested_at = %s,
requested_count = requested_count + 1
WHERE key = %s""",
hostmask, int(time.time()), key)
db.commit()
def removeFactoid(self, channel, key):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""DELETE FROM factoids WHERE key LIKE %s""",
key)
db.commit()
def locked(self, channel, key):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute ("""SELECT locked_by FROM factoids
WHERE key LIKE %s""", key)
if cursor.fetchone()[0] is None:
return False
else:
return True
def lock(self, channel, key, locker_id):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""UPDATE factoids
SET locked_by=%s, locked_at=%s
WHERE key LIKE %s""",
locker_id, int(time.time()), key)
db.commit()
def unlock(self, channel, key):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""UPDATE factoids
SET locked_by=%s, locked_at=%s
WHERE key LIKE %s""", None, None, key)
db.commit()
def mostAuthored(self, channel, limit):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""SELECT created_by, count(key) FROM factoids
GROUP BY created_by
ORDER BY count(key) DESC LIMIT %s""", limit)
return cursor.fetchall()
def mostRecent(self, channel, limit):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""SELECT key FROM factoids
ORDER BY created_at DESC LIMIT %s""", limit)
return cursor.fetchall()
def mostPopular(self, channel, limit):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""SELECT key, requested_count FROM factoids
WHERE requested_count > 0
ORDER BY requested_count DESC LIMIT %s""", limit)
if cursor.rowcount == 0:
return None
else:
return cursor.fetchall()
def getKeysByAuthor(self, channel, author_id):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""SELECT key FROM factoids WHERE created_by=%s
ORDER BY key""", author_id)
if cursor.rowcount == 0:
return None
else:
return cursor.fetchall()
def getKeysByGlob(self, channel, glob):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""SELECT key FROM factoids WHERE key LIKE %s
ORDER BY key""", glob)
if cursor.rowcount == 0:
return None
else:
return cursor.fetchall()
def getKeysByValueGlob(self, channel, glob):
db = self._getDb(channel)
cursor = db.cursor()
cursor.execute("""SELECT key FROM factoids WHERE fact LIKE %s
ORDER BY key""", glob)
if cursor.rowcount == 0:
return None
else:
return cursor.fetchall()
def MoobotDB():
return SqliteMoobotDB()
class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp): class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
priority = 98 priority = 98
addressedRegexps = ['changeFactoid', 'augmentFactoid', addressedRegexps = ['changeFactoid', 'augmentFactoid',
'replaceFactoid', 'addFactoid'] 'replaceFactoid', 'addFactoid']
def __init__(self): def __init__(self):
self.db = MoobotDB()
callbacks.PrivmsgCommandAndRegexp.__init__(self) callbacks.PrivmsgCommandAndRegexp.__init__(self)
self.dbHandler = MoobotDBHandler(dbfilename)
def die(self):
# Handle DB stuff
self.dbHandler.die()
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
@ -180,50 +331,36 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
newfact = plugins.standardSubstitute(irc, msg, newfact) newfact = plugins.standardSubstitute(irc, msg, newfact)
return (type, newfact) return (type, newfact)
def updateFactoidRequest(self, key, hostmask):
"""Updates the last_requested_* fields of a factoid row"""
db = self.dbHandler.getDb()
cursor = db.cursor()
cursor.execute("""UPDATE factoids SET
last_requested_by = %s,
last_requested_at = %s,
requested_count = requested_count +1
WHERE key = %s""",
hostmask, int(time.time()), key)
db.commit()
def randomfactoid(self, irc, msg, args): def randomfactoid(self, irc, msg, args):
"""takes no arguments """takes no arguments
Displays a random factoid (along with its key) from the database. Displays a random factoid (along with its key) from the database.
""" """
db = self.dbHandler.getDb() channel = privmsgs.getChannel(msg, args)
cursor = db.cursor() tup = self.db.randomFactoid(channel)
cursor.execute("""SELECT fact, key FROM factoids if tup is None:
ORDER BY random() LIMIT 1""")
if cursor.rowcount == 0:
irc.error('No factoids in the database.') irc.error('No factoids in the database.')
return else:
(fact, key) = cursor.fetchone() irc.reply('"%s" is "%s"' % tup)
irc.reply('"%s" is "%s"' % (key, fact))
def invalidCommand(self, irc, msg, tokens): def invalidCommand(self, irc, msg, tokens):
key = ' '.join(tokens) key = ' '.join(tokens)
key = key.rstrip('?!') key = key.rstrip('?!')
channel = privmsgs.getChannel(msg, list(msg.args))
# ignore ACTIONs
if key.startswith('\x01'): if key.startswith('\x01'):
return return
# Check the factoid db for an appropriate reply # Check the factoid db for an appropriate reply
db = self.dbHandler.getDb() fact = self.db.getFactoid(channel, key)
cursor = db.cursor() if not fact:
cursor.execute("""SELECT fact FROM factoids WHERE key LIKE %s""", key)
if cursor.rowcount == 0:
return False return False
else: else:
fact = cursor.fetchone()[0] # getFactoid returns "all results", so we need to extract the
# first one
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.updateFactoidRequest(key, hostmask) 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":
@ -238,18 +375,12 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
def addFactoid(self, irc, msg, match): def addFactoid(self, irc, msg, match):
r"^(?!\x01)(.+?)\s+(?:is|_is_)\s+(.+)" r"^(?!\x01)(.+?)\s+(?:is|_is_)\s+(.+)"
# Check and see if there is a command that matches this that didn't
# get caught due to nesting
# cb = callbacks.findCallbackForCommand(irc, msg)
# if cb:
# irc.reply(irc.getHelp(cb[0].config))
# return
# First, check and see if the entire message matches a factoid key # First, check and see if the entire message matches a factoid key
db = self.dbHandler.getDb() channel = privmsgs.getChannel(msg, list(msg.args))
cursor = db.cursor()
key = match.group().rstrip('?! ') key = match.group().rstrip('?! ')
cursor.execute("""SELECT * FROM factoids WHERE key LIKE %s""", key) fact = self.db.getFactoid(channel, key)
if cursor.rowcount != 0: # If it exists, call invalidCommand to display it
if fact:
self.invalidCommand(irc, msg, callbacks.tokenize(match.group())) self.invalidCommand(irc, msg, callbacks.tokenize(match.group()))
return return
# Okay, we are REALLY adding stuff # Okay, we are REALLY adding stuff
@ -259,24 +390,20 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
except KeyError: except KeyError:
irc.errorNotRegistered() irc.errorNotRegistered()
return return
key, fact = match.groups() key, newfact = match.groups()
# These are okay, unless there's an _is_ in there, in which case # These are okay, unless there's an _is_ in there, in which case
# we split on the leftmost one. # we split on the leftmost one.
if '_is_' in match.group(): if '_is_' in match.group():
key, fact = imap(str.strip, match.group().split('_is_', 1)) key, newfact = imap(str.strip, match.group().split('_is_', 1))
# Strip the key of punctuation and spaces # Strip the key of punctuation and spaces
key = key.rstrip('?! ') 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
cursor.execute("""SELECT * FROM factoids WHERE key LIKE %s""", key) fact = self.db.getFactoid(channel, key)
if cursor.rowcount != 0: if fact:
irc.error('Factoid "%s" already exists.' % key) irc.error('Factoid "%s" already exists.' % key)
return return
# Otherwise, # Otherwise,
cursor.execute("""INSERT INTO factoids VALUES self.db.addFactoid(channel, key, newfact, id)
(%s, %s, %s, NULL, NULL, NULL, NULL, NULL, NULL,
%s, 0)""",
key, id, int(time.time()), fact)
db.commit()
irc.replySuccess() irc.replySuccess()
def changeFactoid(self, irc, msg, match): def changeFactoid(self, irc, msg, match):
@ -288,17 +415,15 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
irc.errorNotRegistered() irc.errorNotRegistered()
return return
key, regexp = match.groups() key, regexp = match.groups()
db = self.dbHandler.getDb() channel = privmsgs.getChannel(msg, list(msg.args))
cursor = db.cursor()
# Check and make sure it's in the DB # Check and make sure it's in the DB
cursor.execute("""SELECT locked_at, fact FROM factoids fact = self.db.getFactoid(channel, key)
WHERE key LIKE %s""", key) if not fact:
if cursor.rowcount == 0:
irc.error('Factoid "%s" not found.' % key) irc.error('Factoid "%s" not found.' % key)
return return
# No dice if it's locked, no matter who it is # No dice if it's locked, no matter who it is
(locked_at, fact) = cursor.fetchone() locked = self.db.locked(channel, key)
if locked_at is not None: if locked:
irc.error('Factoid "%s" is locked.' % key) irc.error('Factoid "%s" is locked.' % key)
return return
# It's fair game if we get to here # It's fair game if we get to here
@ -307,12 +432,9 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
except ValueError, e: except ValueError, e:
irc.error('Invalid regexp: "%s"' % regexp) irc.error('Invalid regexp: "%s"' % regexp)
return return
fact = fact[0]
new_fact = r(fact) new_fact = r(fact)
cursor.execute("""UPDATE factoids self.db.updateFactoid(channel, key, new_fact, id)
SET fact = %s, modified_by = %s,
modified_at = %s WHERE key = %s""",
new_fact, id, int(time.time()), key)
db.commit()
irc.replySuccess() irc.replySuccess()
def augmentFactoid(self, irc, msg, match): def augmentFactoid(self, irc, msg, match):
@ -324,26 +446,21 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
irc.errorNotRegistered() irc.errorNotRegistered()
return return
key, new_text = match.groups() key, new_text = match.groups()
db = self.dbHandler.getDb() channel = privmsgs.getChannel(msg, list(msg.args))
cursor = db.cursor() fact = self.db.getFactoid(channel, key)
# Check and make sure it's in the DB # Check and make sure it's in the DB
cursor.execute("""SELECT locked_at, fact FROM factoids if not fact:
WHERE key LIKE %s""", key)
if cursor.rowcount == 0:
irc.error('Factoid "%s" not found.' % key) irc.error('Factoid "%s" not found.' % key)
return return
# No dice if it's locked, no matter who it is # No dice if it's locked, no matter who it is
(locked_at, fact) = cursor.fetchone() locked = self.db.locked(channel, key)
if locked_at is not None: if locked:
irc.error('Factoid "%s" is locked.' % key) irc.error('Factoid "%s" is locked.' % key)
return return
# It's fair game if we get to here # It's fair game if we get to here
fact = fact[0]
new_fact = "%s, or %s" % (fact, new_text) new_fact = "%s, or %s" % (fact, new_text)
cursor.execute("""UPDATE factoids self.db.updateFactoid(channel, key, new_fact, id)
SET fact = %s, modified_by = %s,
modified_at = %s WHERE key = %s""",
new_fact, id, int(time.time()), key)
db.commit()
irc.replySuccess() irc.replySuccess()
def replaceFactoid(self, irc, msg, match): def replaceFactoid(self, irc, msg, match):
@ -360,29 +477,20 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
if '_is_' in match.group(): if '_is_' in match.group():
key, new_fact = imap(str.strip, match.group().split('_is_', 1)) key, new_fact = imap(str.strip, match.group().split('_is_', 1))
key = key.split(' ', 1)[1] # Take out everything to first space key = key.split(' ', 1)[1] # Take out everything to first space
db = self.dbHandler.getDb()
cursor = db.cursor()
# Check and make sure it's in the DB # Check and make sure it's in the DB
cursor.execute("""SELECT locked_at, fact FROM factoids channel = privmsgs.getChannel(msg, list(msg.args))
WHERE key LIKE %s""", key) fact = self.db.getFactoid(channel, key)
if cursor.rowcount == 0: if not fact:
irc.error('Factoid "%s" not found.' % key) irc.error('Factoid "%s" not found.' % key)
return return
# No dice if it's locked, no matter who it is # No dice if it's locked, no matter who it is
(locked_at, _) = cursor.fetchone() locked = self.db.locked(channel, key)
if locked_at is not None: if locked:
irc.error('Factoid "%s" is locked.' % key) irc.error('Factoid "%s" is locked.' % key)
return return
# It's fair game if we get to here # It's fair game if we get to here
cursor.execute("""UPDATE factoids self.db.removeFactoid(channel, key)
SET fact = %s, created_by = %s, self.db.addFactoid(channel, key, new_fact, id)
created_at = %s, modified_by = NULL,
modified_at = NULL, requested_count = 0,
last_requested_by = NULL, last_requested_at = NULL,
locked_at = NULL
WHERE key = %s""",
new_fact, id, int(time.time()), key)
db.commit()
irc.replySuccess() irc.replySuccess()
def literal(self, irc, msg, args): def literal(self, irc, msg, args):
@ -391,15 +499,13 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
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 = privmsgs.getChannel(msg, args)
key = privmsgs.getArgs(args, required=1) key = privmsgs.getArgs(args, required=1)
db = self.dbHandler.getDb() fact = self.db.getFactoid(channel, key)
cursor = db.cursor() if not fact:
cursor.execute("""SELECT fact FROM factoids WHERE key LIKE %s""", key)
if cursor.rowcount == 0:
irc.error('No such factoid: "%s"' % key) irc.error('No such factoid: "%s"' % key)
return
else: else:
fact = cursor.fetchone()[0] fact = fact[0]
irc.reply(fact) irc.reply(fact)
def factinfo(self, irc, msg, args): def factinfo(self, irc, msg, args):
@ -407,22 +513,17 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
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 = privmsgs.getChannel(msg, args)
key = privmsgs.getArgs(args, required=1) key = privmsgs.getArgs(args, required=1)
# 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
db = self.dbHandler.getDb() info = self.db.getFactinfo(channel, key)
cursor = db.cursor() if not info:
cursor.execute("""SELECT created_by, created_at, modified_by,
modified_at, last_requested_by, last_requested_at,
requested_count, locked_by, locked_at FROM
factoids WHERE key LIKE %s""", key)
if cursor.rowcount == 0:
irc.error('No such factoid: "%s"' % key) irc.error('No such factoid: "%s"' % key)
return return
(created_by, created_at, modified_by, modified_at, last_requested_by, (created_by, created_at, modified_by, modified_at, last_requested_by,
last_requested_at, requested_count, locked_by, last_requested_at, requested_count, locked_by, locked_at) = info
locked_at) = cursor.fetchone()
# First, creation info. # First, creation info.
# Map the integer created_by to the username # Map the integer created_by to the username
creat_by = ircdb.users.getUser(created_by).name creat_by = ircdb.users.getUser(created_by).name
@ -460,15 +561,13 @@ 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)
key = privmsgs.getArgs(args, required=1) key = privmsgs.getArgs(args, required=1)
db = self.dbHandler.getDb() info = self.db.getFactinfo(channel, key)
cursor = db.cursor() if not info:
cursor.execute("""SELECT created_by, locked_by FROM factoids
WHERE key LIKE %s""", key)
if cursor.rowcount == 0:
irc.error('No such factoid: "%s"' % key) irc.error('No such factoid: "%s"' % key)
return return
(created_by, locked_by) = cursor.fetchone() (created_by, _, _, _, _, _, _, locked_by, _) = info
# Don't perform redundant operations # Don't perform redundant operations
if locking and locked_by is not None: if locking and locked_by is not None:
irc.error('Factoid "%s" is already locked.' % key) irc.error('Factoid "%s" is already locked.' % key)
@ -489,13 +588,9 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
return return
# Okay, we're done, ready to lock/unlock # Okay, we're done, ready to lock/unlock
if locking: if locking:
locked_at = int(time.time()) self.db.lock(channel, key, id)
else: else:
locked_at = None self.db.unlock(channel, key)
id = None
cursor.execute("""UPDATE factoids SET locked_at = %s, locked_by = %s
WHERE key = %s""", locked_at, id, key)
db.commit()
irc.replySuccess() irc.replySuccess()
def lock(self, irc, msg, args): def lock(self, irc, msg, args):
@ -514,8 +609,7 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
""" """
self._lock(irc, msg, args, False) self._lock(irc, msg, args, False)
_mostCount = 10 class MostException:
class MostException(Exception):
pass pass
def most(self, irc, msg, args): def most(self, irc, msg, args):
"""<popular|authored|recent> """<popular|authored|recent>
@ -524,46 +618,35 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
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 = privmsgs.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
db = self.dbHandler.getDb() limit = self.registryValue('mostCount', channel)
cursor = db.cursor() irc.reply(method(channel, limit))
cursor.execute("""SELECT COUNT(*) FROM factoids""")
if int(cursor.fetchone()[0]) == 0:
irc.error('I don\'t have any factoids in my database!')
else:
try:
irc.reply(method(cursor, self._mostCount))
except self.MostException, e:
irc.error(str(e))
def _mostAuthored(self, cursor, limit):
cursor.execute("""SELECT created_by, count(key) FROM factoids def _mostAuthored(self, channel, limit):
GROUP BY created_by results = self.db.mostAuthored(channel, limit)
ORDER BY count(key) DESC LIMIT %s""", 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 cursor.fetchall()] for t in results]
return 'Most prolific %s: %s' % \ return 'Most prolific %s: %s' % \
(utils.pluralize('author', len(L)), utils.commaAndify(L)) (utils.pluralize('author', len(L)), utils.commaAndify(L))
def _mostRecent(self, cursor, limit): def _mostRecent(self, channel, limit):
cursor.execute("""SELECT key FROM factoids results = self.db.mostRecent(channel, limit)
ORDER by created_at DESC LIMIT %s""", limit) L = ['"%s"' % t[0] for t in results]
L = ['"%s"' % t[0] for t in cursor.fetchall()]
return '%s: %s' % \ return '%s: %s' % \
(utils.nItems('factoid', len(L), between='latest'), (utils.nItems('factoid', len(L), between='latest'),
utils.commaAndify(L)) utils.commaAndify(L))
def _mostPopular(self, cursor, limit): def _mostPopular(self, channel, limit):
cursor.execute("""SELECT key, requested_count FROM factoids results = self.db.mostPopular(channel, limit)
WHERE requested_count > 0 if not results:
ORDER BY requested_count DESC LIMIT %s""", limit)
if cursor.rowcount == 0:
raise self.MostException, 'No factoids have been requested.' raise self.MostException, 'No factoids have been requested.'
L = ['"%s" (%s)' % (t[0], t[1]) for t in cursor.fetchall()] L = ['"%s" (%s)' % (t[0], t[1]) for t in results]
return 'Top %s: %s' % \ return 'Top %s: %s' % \
(utils.nItems('factoid', len(L), between='requested'), (utils.nItems('factoid', len(L), between='requested'),
utils.commaAndify(L)) utils.commaAndify(L))
@ -575,21 +658,18 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
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 = privmsgs.getChannel(msg, args)
author = privmsgs.getArgs(args, required=1) author = privmsgs.getArgs(args, required=1)
try: try:
id = ircdb.users.getUserId(author) id = ircdb.users.getUserId(author)
except KeyError: except KeyError:
irc.error("No such user: %r" % author) irc.error("No such user: %r" % author)
return return
db = self.dbHandler.getDb() results = self.db.getKeysByAuthor(channel, id)
cursor = db.cursor() if not results:
cursor.execute("""SELECT key FROM factoids
WHERE created_by = %s
ORDER BY key""", id)
if cursor.rowcount == 0:
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 cursor.fetchall()] keys = ['"%s"' % tup[0] for tup 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)
@ -599,24 +679,20 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
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 = privmsgs.getChannel(msg, args)
search = privmsgs.getArgs(args, required=1) search = privmsgs.getArgs(args, required=1)
# Don't error if we aren't in a channel, private messages are okay # Don't error if we aren't in a channel, private messages are okay
channel = privmsgs.getChannel(msg, args, raiseError=False) channel = privmsgs.getChannel(msg, args, raiseError=False)
glob = '%' + search + '%' glob = '%' + search + '%'
db = self.dbHandler.getDb() results = self.db.getKeysByGlob(channel, glob)
cursor = db.cursor() if not results:
cursor.execute("""SELECT key FROM factoids
WHERE key LIKE %s
ORDER BY key""",
glob)
if cursor.rowcount == 0:
irc.reply('No keys matching "%s" found.' % search) irc.reply('No keys matching "%s" found.' % search)
elif cursor.rowcount == 1 and \ elif len(results) == 1 and \
self.registryValue('showFactoidIfOnlyOneMatch', channel): self.registryValue('showFactoidIfOnlyOneMatch', channel):
key = cursor.fetchone()[0] key = results[0][0]
self.invalidCommand(irc, msg, [key]) self.invalidCommand(irc, msg, [key])
else: else:
keys = ['"%s"' % tup[0] for tup in cursor.fetchall()] keys = ['"%s"' % tup[0] for tup in results]
s = 'Key search for "%s" (%s found): %s' % \ s = 'Key search for "%s" (%s found): %s' % \
(search, len(keys), utils.commaAndify(keys)) (search, len(keys), utils.commaAndify(keys))
irc.reply(s) irc.reply(s)
@ -626,18 +702,14 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
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 = privmsgs.getChannel(msg, args)
search = privmsgs.getArgs(args, required=1) search = privmsgs.getArgs(args, required=1)
glob = '%' + search + '%' glob = '%' + search + '%'
db = self.dbHandler.getDb() results = self.db.getKeysByValueGlob(channel, glob)
cursor = db.cursor() if not results:
cursor.execute("""SELECT key FROM factoids
WHERE fact LIKE %s
ORDER BY key""",
glob)
if cursor.rowcount == 0:
irc.reply('No values matching "%s" found.' % search) irc.reply('No values matching "%s" found.' % search)
return return
keys = ['"%s"' % tup[0] for tup in cursor.fetchall()] keys = ['"%s"' % tup[0] for tup in results]
s = 'Value search for "%s" (%s found): %s' % \ s = 'Value search for "%s" (%s found): %s' % \
(search, len(keys), utils.commaAndify(keys)) (search, len(keys), utils.commaAndify(keys))
irc.reply(s) irc.reply(s)
@ -653,20 +725,17 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
except KeyError: except KeyError:
irc.errorNotRegistered() irc.errorNotRegistered()
return return
channel = privmsgs.getChannel(msg, args)
key = privmsgs.getArgs(args, required=1) key = privmsgs.getArgs(args, required=1)
db = self.dbHandler.getDb() fact = self.db.getFactoid(channel, key)
cursor = db.cursor() if not fact:
cursor.execute("""SELECT key, locked_at FROM factoids
WHERE key LIKE %s""", key)
if cursor.rowcount == 0:
irc.error('No such factoid: "%s"' % key) irc.error('No such factoid: "%s"' % key)
return return
(_, locked_at) = cursor.fetchone() locked = self.db.locked(channel, key)
if locked_at is not None: if locked:
irc.error("Factoid is locked, cannot remove.") irc.error("Factoid is locked, cannot remove.")
return return
cursor.execute("""DELETE FROM factoids WHERE key = %s""", key) self.db.removeFactoid(channel, key)
db.commit()
irc.replySuccess() irc.replySuccess()
def randomfactoid(self, irc, msg, args): def randomfactoid(self, irc, msg, args):
@ -674,14 +743,12 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
Displays a random factoid (along with its key) from the database. Displays a random factoid (along with its key) from the database.
""" """
db = self.dbHandler.getDb() channel = privmsgs.getChannel(msg, args)
cursor = db.cursor() results = self.db.randomFactoid(channel)
cursor.execute("""SELECT fact, key FROM factoids if not results:
ORDER BY random() LIMIT 1""")
if cursor.rowcount == 0:
irc.error('No factoids in the database.') irc.error('No factoids in the database.')
return return
(fact, key) = cursor.fetchone() (fact, key) = results
irc.reply('Random factoid: "%s" is "%s"' % (key, fact)) irc.reply('Random factoid: "%s" is "%s"' % (key, fact))
Class = MoobotFactoids Class = MoobotFactoids