info = { 'author': 'Jon Bergli Heier', 'title': 'IRC Quotes', 'description': 'Allows users to access a quote database.', } import random, time, re import psycopg2 class Quotes: def __init__(self, db = None): self.randseed = False self.connect(db) def format_quote(self, q): return q def connect(self, db): self.db = psycopg2.connect(database = 'fot') self.updatecount() def updatecount(self): cur = self.db.cursor() cur.execute('select count(id) from quotes') self.count = int(cur.fetchone()[0]) cur.close() def add(self, nick, quote): cur = self.db.cursor() cur.execute('insert into quotes (nick, date, quote) values (%s, %s, %s)', (nick, int(time.time()), quote)) cur.execute('select currval(\'quotes_id_seq\')') lastrowid = cur.fetchone()[0] cur.close() self.db.commit() return lastrowid def delete(self, qid = None): cur = self.db.cursor() cur.execute('delete from quotes where id = %s limit 1', (qid,)) cur.close() self.db.commit() def find(self, search, func = None): search = re.compile(search) if func == 'rfind' else search.lower() if func == 'efind' else [x.lower() for x in search.split(' ')] dosearch = lambda quote: search.search(quote) != None if func == 'rfind' else search in quote if func == 'efind' else len([x for x in search if x in quote]) if func == 'afind' else len([x for x in search if x in quote]) == len(search) cur = self.db.cursor() cur.execute('select id, quote from quotes order by id asc') ret = [] i = 0 for q in cur.fetchall(): i += 1 if dosearch(q[1].lower()): ret.append((q[0], self.format_quote(q[1]))) cur.close() return ret def get(self, qid = None): cur = self.db.cursor() if not qid: if not self.randseed: random.seed() self.randseed = True n = random.randint(1, self.count) cur.execute('select id, quote from quotes order by id asc limit 1 offset %s', (n - 1,)) else: qid = int(qid) cur.execute('select quote from quotes where id = %s limit 1', (qid,)) s = cur.fetchone() cur.close() if s and len(s) == 2: qid, s = s elif s: s = s[0] return (qid, self.format_quote(s)) if s else (None, None) def info(self, qid): cur = self.db.cursor() cur.execute('select id, nick, date, quote from quotes where id = %s limit 1', (qid,)) s = cur.fetchone() cur.close() return s if s else None def range(self, p, pp): cur = self.db.cursor() cur.execute('select id from quotes order by id asc limit %s offset %s', (pp, (p - 1) * pp)) s = cur.fetchall() cur.close() return [x[0] for x in s] def format_date(self, d): return time.strftime('%c', time.localtime(d)) if d else '(Unknown date)' class IRCHandler(Quotes): def add(self, *args): 'Add a quote to the database.' quote = ' '.join(args) qid = Quotes.add(self, self.nick, quote) yield '\002Quote #%d\002 has been added' % (qid) def format_quote(self, quote): return quote def output(self, quotes): for n, q in quotes: yield '\002Quote #%d:\002 %s' % (n, q) def _find(self, args, func = 'find'): if not len(args): yield 'Quote: Missing search pattern.' return args = ' '.join(args) results = Quotes.find(self, args, func) leftovers = [] if len(results) > 1: yield 'Quote: Found \002%d\002 results for "%s"%s' % (len(results), args, ', here are the last two:' if len(results) > 3 else ':' if len(results) else '') if len(results): if len(results) > 3: leftovers, results = results[:-2], results[-2:] for l in self.output(results): yield l if leftovers: yield 'Other quotes: %s' % ', '.join(['#%d' % x[0] for x in leftovers]) def find(self, *args): 'Find quotes containing all given words.' return self._find(args) def afind(self, *args): 'Find quotes containing any given word.' return self._find(args, 'afind') def efind(self, *args): 'Find quotes containing the exact given phrase.' return self._find(args, 'efind') def rfind(self, *args): 'Find quotes using regexp search.' return self._find(args, 'rfind') def get(self, *args): 'Print a quote.' if not len(args): yield 'Quote: Missing quote number.' return args = args[0] if args[0] == '#': args = args[1:] if not args.isdigit(): yield 'Quote: Identifier must be a number.' return qid = int(args) qid, q = Quotes.get(self, qid) if not q: yield 'Quote: That quote does not exist.' else: for l in self.output(((qid, q),)): yield l def help(self, *args): 'Show this help.' funcs = ('random', 'get id', 'info id', 'find text', 'afind text', 'efind text', 'rfind regexp', 'add text', 'stats', 'help') l = [] maxlen = 0 for i in funcs: name = i.split(' ') if len(name) == 2: name, arg = name else: name, arg = name[0], None l.append(('%s <%s>' % (name, arg) if arg else name, getattr(self, name).__doc__)) if len(l[-1][0]) > maxlen: maxlen = len(l[-1][0]) return ('%s%s%s' % (x[0], ' ' * (maxlen - len(x[0]) + 1), x[1]) for x in l) def info(self, *args): 'Print stored information about a quote.' if not len(args): yield 'Quote: Missing quote number.' return elif not args[0].isdigit(): yield 'Quote: Identifier must by a number.' return n = int(args[0]) info = Quotes.info(self, n) if not info: yield 'Quote: That quote does not exist.' else: yield '\002Quote #%d\002 was added by %s at %s.' % (n, str(info[1]) if info[1] else '(unknown nick)', self.format_date(info[2]) if info[2] else '(unknown date)') def random(self, *args): 'Print a random quote. (Default)' return self.output((Quotes.get(self), )) def stats(self, *args): 'Print quote stats.' yield 'There are \002%d\002 quotes in the database.' % (self.count) quote_handler = IRCHandler() class Module: def __init__(self, bot): self.irc = bot self.irc.register_keyword('!quote', self) def keyword(self, nick, channel, kw, msg): args = msg.split(' ') cmd = args[0] if len(args) and len(args[0].strip()) else 'random' args = args[1:] if cmd.isdigit() or (cmd[0] == '#' and cmd[1:].isdigit()): cmd, args = 'get', [cmd] quote_handler.nick = nick.split('!')[0] if hasattr(quote_handler, cmd) and callable(getattr(quote_handler, cmd)): for line in getattr(quote_handler, cmd)(*args): self.irc.msg(channel if not channel == self.irc.nickname else nick.split('!')[0], line) else: self.irc.msg(channel if not channel == self.irc.nickname else nick.split('!')[0], '%s, invalid command "%s"' % (nick.split('!')[0], cmd))