2003-03-12 07:26:59 +01:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
###
|
|
|
|
# Copyright (c) 2002, Jeremiah Fincher
|
|
|
|
# All rights reserved.
|
|
|
|
#
|
|
|
|
# Redistribution and use in source and binary forms, with or without
|
|
|
|
# modification, are permitted provided that the following conditions are met:
|
|
|
|
#
|
|
|
|
# * Redistributions of source code must retain the above copyright notice,
|
|
|
|
# this list of conditions, and the following disclaimer.
|
|
|
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
# this list of conditions, and the following disclaimer in the
|
|
|
|
# documentation and/or other materials provided with the distribution.
|
|
|
|
# * Neither the name of the author of this software nor the name of
|
|
|
|
# contributors to this software may be used to endorse or promote products
|
|
|
|
# derived from this software without specific prior written consent.
|
|
|
|
#
|
|
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
###
|
|
|
|
|
2003-03-25 07:53:51 +01:00
|
|
|
"""
|
|
|
|
Maintains a Quotes database for each channel.
|
|
|
|
"""
|
|
|
|
|
2003-11-25 09:23:47 +01:00
|
|
|
__revision__ = "$Id$"
|
|
|
|
|
2003-10-05 14:56:56 +02:00
|
|
|
import plugins
|
2003-03-12 07:26:59 +01:00
|
|
|
|
|
|
|
import re
|
|
|
|
import time
|
2003-08-26 19:07:37 +02:00
|
|
|
import getopt
|
2003-03-12 07:26:59 +01:00
|
|
|
import os.path
|
|
|
|
|
2003-10-04 15:53:13 +02:00
|
|
|
import conf
|
2003-08-26 19:07:37 +02:00
|
|
|
import utils
|
2003-03-12 07:26:59 +01:00
|
|
|
import ircdb
|
|
|
|
import privmsgs
|
|
|
|
import callbacks
|
|
|
|
|
2003-12-04 00:48:00 +01:00
|
|
|
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/>'
|
|
|
|
|
2003-11-08 10:28:02 +01:00
|
|
|
class Quotes(plugins.ChannelDBHandler, callbacks.Privmsg):
|
2003-03-12 07:26:59 +01:00
|
|
|
def __init__(self):
|
2003-10-05 14:56:56 +02:00
|
|
|
plugins.ChannelDBHandler.__init__(self)
|
2003-03-12 07:26:59 +01:00
|
|
|
callbacks.Privmsg.__init__(self)
|
|
|
|
|
|
|
|
def makeDb(self, filename):
|
|
|
|
if os.path.exists(filename):
|
|
|
|
return sqlite.connect(db=filename, mode=0755,
|
|
|
|
converters={'bool': bool})
|
|
|
|
#else:
|
|
|
|
db = sqlite.connect(db=filename, mode=0755, coverters={'bool': bool})
|
|
|
|
cursor = db.cursor()
|
|
|
|
cursor.execute("""CREATE TABLE quotes (
|
|
|
|
id INTEGER PRIMARY KEY,
|
2003-08-26 19:07:37 +02:00
|
|
|
added_by TEXT,
|
2003-03-12 07:26:59 +01:00
|
|
|
added_at TIMESTAMP,
|
2003-08-26 19:07:37 +02:00
|
|
|
quote TEXT
|
|
|
|
);""")
|
2003-03-12 07:26:59 +01:00
|
|
|
db.commit()
|
|
|
|
return db
|
|
|
|
|
2003-10-21 07:19:54 +02:00
|
|
|
def add(self, irc, msg, args):
|
2003-08-26 19:07:37 +02:00
|
|
|
"""[<channel>] <quote>
|
|
|
|
|
|
|
|
Adds <quote> to the quotes database for <channel>. <channel> is only
|
|
|
|
necessary if the message isn't sent in the channel itself.
|
|
|
|
"""
|
2003-03-12 07:26:59 +01:00
|
|
|
channel = privmsgs.getChannel(msg, args)
|
|
|
|
quote = privmsgs.getArgs(args)
|
|
|
|
db = self.getDb(channel)
|
|
|
|
cursor = db.cursor()
|
2003-09-12 12:54:25 +02:00
|
|
|
quotetime = int(time.time())
|
2003-03-12 07:26:59 +01:00
|
|
|
cursor.execute("""INSERT INTO quotes
|
|
|
|
VALUES(NULL, %s, %s, %s)""",
|
2003-09-12 12:54:25 +02:00
|
|
|
msg.nick, quotetime, quote)
|
2003-03-12 07:26:59 +01:00
|
|
|
db.commit()
|
2003-10-29 09:38:15 +01:00
|
|
|
sql = """SELECT id FROM quotes
|
|
|
|
WHERE added_by=%s AND added_at=%s AND quote=%s"""
|
|
|
|
cursor.execute(sql, msg.nick, quotetime, quote)
|
2003-09-12 12:54:25 +02:00
|
|
|
quoteid = cursor.fetchone()[0]
|
2004-01-09 00:03:48 +01:00
|
|
|
irc.replySuccess('(Quote #%s added)' % quoteid)
|
2003-03-12 07:26:59 +01:00
|
|
|
|
2004-01-18 09:19:44 +01:00
|
|
|
def stats(self, irc, msg, args):
|
2003-08-26 19:07:37 +02:00
|
|
|
"""[<channel>]
|
|
|
|
|
|
|
|
Returns the numbers of quotes in the quote database for <channel>.
|
|
|
|
<channel> is only necessary if the message isn't sent in the channel
|
|
|
|
itself.
|
|
|
|
"""
|
2003-03-12 07:26:59 +01:00
|
|
|
channel = privmsgs.getChannel(msg, args)
|
|
|
|
db = self.getDb(channel)
|
|
|
|
cursor = db.cursor()
|
2003-08-26 20:10:17 +02:00
|
|
|
cursor.execute("""SELECT COUNT(*) FROM quotes""")
|
2003-08-26 19:07:37 +02:00
|
|
|
maxid = int(cursor.fetchone()[0])
|
2003-03-12 07:26:59 +01:00
|
|
|
if maxid is None:
|
|
|
|
maxid = 0
|
2003-12-12 16:41:33 +01:00
|
|
|
s = 'There %s %s in my database.' % \
|
|
|
|
(utils.be(maxid), utils.nItems('quote', maxid))
|
2004-01-08 04:12:14 +01:00
|
|
|
irc.reply(s)
|
2003-03-12 07:26:59 +01:00
|
|
|
|
2003-11-03 07:36:18 +01:00
|
|
|
def get(self, irc, msg, args):
|
2003-09-23 00:11:05 +02:00
|
|
|
"""[<channel>] --{id,regexp,from,with}=<value> ]
|
2003-08-26 19:07:37 +02:00
|
|
|
|
|
|
|
Returns quote(s) matching the given criteria. --from is who added the
|
|
|
|
quote; --id is the id number of the quote; --regexp is a regular
|
|
|
|
expression to search for.
|
|
|
|
"""
|
2003-03-12 07:26:59 +01:00
|
|
|
channel = privmsgs.getChannel(msg, args)
|
2003-09-23 00:11:05 +02:00
|
|
|
(optlist, rest) = getopt.getopt(args, '', ['id=', 'regexp=',
|
|
|
|
'from=', 'with='])
|
2003-08-26 19:07:37 +02:00
|
|
|
if not optlist and not rest:
|
|
|
|
raise callbacks.ArgumentError
|
|
|
|
criteria = []
|
|
|
|
formats = []
|
|
|
|
predicateName = ''
|
2003-03-12 07:26:59 +01:00
|
|
|
db = self.getDb(channel)
|
2003-08-26 19:07:37 +02:00
|
|
|
for (option, argument) in optlist:
|
|
|
|
option = option.lstrip('-')
|
|
|
|
if option == 'id':
|
|
|
|
try:
|
|
|
|
argument = int(argument)
|
|
|
|
criteria.append('id=%s' % argument)
|
|
|
|
except ValueError:
|
2004-01-08 04:12:14 +01:00
|
|
|
irc.error('--id value must be an integer.')
|
2003-08-26 19:07:37 +02:00
|
|
|
return
|
2003-09-23 00:11:05 +02:00
|
|
|
elif option == 'with':
|
|
|
|
criteria.append('quote LIKE %s')
|
|
|
|
formats.append('%%%s%%' % argument)
|
2003-08-26 19:07:37 +02:00
|
|
|
elif option == 'from':
|
|
|
|
criteria.append('added_by=%s')
|
|
|
|
formats.append(argument)
|
|
|
|
elif option == 'regexp':
|
|
|
|
try:
|
2003-08-26 20:10:17 +02:00
|
|
|
r = utils.perlReToPythonRe(argument)
|
|
|
|
except ValueError:
|
|
|
|
try:
|
|
|
|
r = re.compile(argument, re.I)
|
|
|
|
except re.error, e:
|
2004-01-08 04:12:14 +01:00
|
|
|
irc.error(str(e))
|
2003-08-26 20:10:17 +02:00
|
|
|
return
|
2003-08-26 19:07:37 +02:00
|
|
|
def p(s):
|
2003-08-26 20:10:17 +02:00
|
|
|
return int(bool(r.search(s)))
|
2003-08-26 19:07:37 +02:00
|
|
|
predicateName += 'p'
|
|
|
|
db.create_function(predicateName, 1, p)
|
|
|
|
criteria.append('%s(quote)' % predicateName)
|
|
|
|
for s in rest:
|
2003-08-26 20:10:17 +02:00
|
|
|
try:
|
|
|
|
i = int(s)
|
|
|
|
criteria.append('id=%s' % i)
|
|
|
|
except ValueError:
|
|
|
|
s = '%%%s%%' % s
|
|
|
|
criteria.append('quote LIKE %s')
|
|
|
|
formats.append(s)
|
2003-08-26 19:07:37 +02:00
|
|
|
sql = """SELECT id, quote FROM quotes
|
|
|
|
WHERE %s""" % ' AND '.join(criteria)
|
2003-03-12 07:26:59 +01:00
|
|
|
cursor = db.cursor()
|
2003-08-26 19:07:37 +02:00
|
|
|
cursor.execute(sql, *formats)
|
|
|
|
if cursor.rowcount == 0:
|
2004-01-08 04:12:14 +01:00
|
|
|
irc.reply('No quotes matched that criteria.')
|
2003-08-26 19:07:37 +02:00
|
|
|
elif cursor.rowcount == 1:
|
|
|
|
(id, quote) = cursor.fetchone()
|
2004-01-08 04:12:14 +01:00
|
|
|
irc.reply('#%s: %s' % (id, quote))
|
2003-08-26 19:07:37 +02:00
|
|
|
elif cursor.rowcount > 10:
|
2004-01-08 04:12:14 +01:00
|
|
|
irc.reply('More than 10 quotes matched your criteria. '
|
2003-08-26 19:07:37 +02:00
|
|
|
'Please narrow your query.')
|
|
|
|
else:
|
|
|
|
results = cursor.fetchall()
|
|
|
|
idsWithSnippets = []
|
|
|
|
for (id, quote) in results:
|
|
|
|
s = '#%s: "%s..."' % (id, quote[:30])
|
|
|
|
idsWithSnippets.append(s)
|
2004-01-08 04:12:14 +01:00
|
|
|
irc.reply(utils.commaAndify(idsWithSnippets))
|
2003-08-26 19:07:37 +02:00
|
|
|
### FIXME: we need to remove those predicates from the database.
|
2003-03-12 07:26:59 +01:00
|
|
|
|
2003-10-21 07:19:54 +02:00
|
|
|
def random(self, irc, msg, args):
|
2003-08-26 19:07:37 +02:00
|
|
|
"""[<channel>]
|
|
|
|
|
|
|
|
Returns a random quote from <channel>. <channel> is only necessary if
|
|
|
|
the message isn't sent in the channel itself.
|
|
|
|
"""
|
2003-03-12 07:26:59 +01:00
|
|
|
channel = privmsgs.getChannel(msg, args)
|
|
|
|
db = self.getDb(channel)
|
|
|
|
cursor = db.cursor()
|
2003-10-04 12:22:36 +02:00
|
|
|
cursor.execute("""SELECT id FROM quotes
|
2003-03-12 07:26:59 +01:00
|
|
|
ORDER BY random()
|
|
|
|
LIMIT 1""")
|
2003-10-11 23:03:02 +02:00
|
|
|
if cursor.rowcount != 1:
|
2004-01-08 04:12:14 +01:00
|
|
|
irc.error('It seems that quote database is empty.')
|
2003-03-25 21:12:27 +01:00
|
|
|
return
|
2003-10-04 12:22:36 +02:00
|
|
|
(id,) = cursor.fetchone()
|
2003-11-03 07:36:18 +01:00
|
|
|
self.get(irc, msg, [channel, '--id', str(id)])
|
2003-03-12 07:26:59 +01:00
|
|
|
|
2003-10-21 07:19:54 +02:00
|
|
|
def info(self, irc, msg, args):
|
2003-08-26 19:07:37 +02:00
|
|
|
"""[<channel>] <id>
|
|
|
|
|
|
|
|
Returns the metadata about the quote <id> in the quotes
|
|
|
|
database for <channel>. <channel> is only necessary if the message
|
|
|
|
isn't sent in the channel itself.
|
|
|
|
"""
|
2003-03-12 07:26:59 +01:00
|
|
|
channel = privmsgs.getChannel(msg, args)
|
|
|
|
id = privmsgs.getArgs(args)
|
|
|
|
db = self.getDb(channel)
|
|
|
|
cursor = db.cursor()
|
|
|
|
cursor.execute("""SELECT * FROM quotes WHERE id=%s""", id)
|
2003-08-26 13:24:06 +02:00
|
|
|
if cursor.rowcount == 1:
|
|
|
|
(id, added_by, added_at, quote) = cursor.fetchone()
|
2004-01-18 08:58:26 +01:00
|
|
|
timestamp = time.strftime(conf.supybot.humanTimestampFormat(),
|
2003-08-26 13:15:15 +02:00
|
|
|
time.localtime(int(added_at)))
|
2004-01-09 00:03:48 +01:00
|
|
|
irc.reply('Quote %r added by %s at %s.' %
|
|
|
|
(quote, added_by, timestamp))
|
2003-03-12 07:26:59 +01:00
|
|
|
else:
|
2004-01-08 04:12:14 +01:00
|
|
|
irc.error('There isn\'t a quote with that id.')
|
2003-03-12 07:26:59 +01:00
|
|
|
|
2004-01-09 00:03:48 +01:00
|
|
|
def remove(self, irc, msg, args):
|
2003-08-26 19:07:37 +02:00
|
|
|
"""[<channel>] <id>
|
|
|
|
|
|
|
|
Removes quote <id> from the quotes database for <channel>. <channel>
|
|
|
|
is only necessary if the message isn't sent in the channel itself.
|
|
|
|
"""
|
2004-01-09 00:03:48 +01:00
|
|
|
channel = privmsgs.getChannel(msg, args)
|
2003-03-12 07:26:59 +01:00
|
|
|
id = privmsgs.getArgs(args)
|
|
|
|
db = self.getDb(channel)
|
|
|
|
cursor = db.cursor()
|
2004-01-08 16:24:56 +01:00
|
|
|
cursor.execute("""DELETE FROM quotes WHERE id=%s""", id)
|
|
|
|
if cursor.rowcount == 0:
|
|
|
|
irc.error('There was no such quote.')
|
2003-03-12 07:26:59 +01:00
|
|
|
else:
|
2004-01-08 16:24:56 +01:00
|
|
|
irc.replySuccess()
|
2003-08-20 18:26:23 +02:00
|
|
|
|
2003-03-12 07:26:59 +01:00
|
|
|
|
|
|
|
Class = Quotes
|
2003-03-24 09:41:19 +01:00
|
|
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|