From 9eb5b236a6646c18a971c53a48e36057cc9628ba Mon Sep 17 00:00:00 2001 From: Ryan Hitchman Date: Mon, 1 Feb 2010 00:29:50 -0700 Subject: [PATCH] rewrite tell, simplify db access in quote, seen, urlhistory. fix wolframalpha for the last time --- core/db.py | 9 +++ plugins/quote.py | 46 +++++------- plugins/seen.py | 32 ++------- plugins/tell.py | 147 +++++++++++++++----------------------- plugins/urlhistory.py | 30 ++++---- plugins/util/timesince.py | 3 + plugins/wolframalpha.py | 2 +- 7 files changed, 109 insertions(+), 160 deletions(-) create mode 100644 core/db.py diff --git a/core/db.py b/core/db.py new file mode 100644 index 0000000..ee04428 --- /dev/null +++ b/core/db.py @@ -0,0 +1,9 @@ +import os +import sqlite3 + +def get_db_connection(server, name='skybot.%s.db'): + "returns an sqlite3 connection to a persistent database" + filename = os.path.join(bot.persist_dir, name % server) + return sqlite3.connect(filename) + +bot.get_db_connection = get_db_connection diff --git a/plugins/quote.py b/plugins/quote.py index 17b0a4c..2fbf09c 100644 --- a/plugins/quote.py +++ b/plugins/quote.py @@ -1,37 +1,27 @@ -import os -import sqlite3 import random import re +import sqlite3 import time from util import hook -dbname = "skybot.db" -def db_connect(db): - conn = sqlite3.connect(db) - conn.execute('''create table if not exists quotes - (server, chan, nick, add_nick, msg, time real, deleted default 0, - primary key (server, chan, nick, msg))''') - conn.commit() - return conn - -def add_quote(conn, server, chan, nick, add_nick, msg): +def add_quote(conn, chan, nick, add_nick, msg): now = time.time() - print repr((conn, server, add_nick, nick, msg, time)) - conn.execute('''insert or fail into quotes (server, chan, nick, add_nick, - msg, time) values(?,?,?,?,?,?)''', - (server, chan, nick, add_nick, msg, now)) + print repr((conn, add_nick, nick, msg, time)) + conn.execute('''insert or fail into quotes (chan, nick, add_nick, + msg, time) values(?,?,?,?,?)''', + (chan, nick, add_nick, msg, now)) conn.commit() -def get_quotes_by_nick(conn, server, chan, nick): +def get_quotes_by_nick(conn, chan, nick): return conn.execute("select time, nick, msg from quotes where deleted!=1 " - "and server=? and chan=? and lower(nick)=lower(?) order by time", - (server, chan, nick)).fetchall() + "and chan=? and lower(nick)=lower(?) order by time", + (chan, nick)).fetchall() -def get_quotes_by_chan(conn, server, chan): +def get_quotes_by_chan(conn, chan): return conn.execute("select time, nick, msg from quotes where deleted!=1 " - "and server=? and chan=? order by time", (server, chan)).fetchall() + "and chan=? order by time", (chan,)).fetchall() def format_quote(q, num, n_quotes): @@ -39,15 +29,17 @@ def format_quote(q, num, n_quotes): return "[%d/%d] %s <%s> %s" % (num, n_quotes, time.strftime("%Y-%m-%d", time.gmtime(ctime)), nick, msg) - @hook.command('q') @hook.command def quote(bot, input): ".q/.quote [#n]/.quote add -- gets " \ "random or [#n]th quote by or from <#chan>/adds quote" - dbpath = os.path.join(bot.persist_dir, dbname) - conn = db_connect(dbpath) + conn = bot.get_db_connection(bot, input.server) + conn.execute('''create table if not exists quotes + (chan, nick, add_nick, msg, time real, deleted default 0, + primary key (chan, nick, msg))''') + conn.commit() try: add = re.match(r"add\s+?\s+(.*)", input.inp, re.I) @@ -57,7 +49,7 @@ def quote(bot, input): if add: nick, msg = add.groups() try: - add_quote(conn, input.server, chan, nick, input.nick, msg) + add_quote(conn, chan, nick, input.nick, msg) except sqlite3.IntegrityError: return "message already stored, doing nothing." return "quote added." @@ -67,9 +59,9 @@ def quote(bot, input): by_chan = False if select.startswith('#'): by_chan = True - quotes = get_quotes_by_chan(conn, input.server, select) + quotes = get_quotes_by_chan(conn, select) else: - quotes = get_quotes_by_nick(conn, input.server, chan, select) + quotes = get_quotes_by_nick(conn, chan, select) n_quotes = len(quotes) diff --git a/plugins/seen.py b/plugins/seen.py index 72b29ef..1088b91 100644 --- a/plugins/seen.py +++ b/plugins/seen.py @@ -1,36 +1,21 @@ " seen.py: written by sklnd in about two beers July 2009" -import os import time -from datetime import datetime -import sqlite3 from util import hook, timesince -dbname = "skybot.db" - - -def adapt_datetime(ts): - return time.mktime(ts.timetuple()) - -sqlite3.register_adapter(datetime, adapt_datetime) - - @hook.tee def seeninput(bot, input): if input.command != 'PRIVMSG': return - dbpath = os.path.join(bot.persist_dir, dbname) - - conn = dbconnect(dbpath) + conn = db_connect(bot, input.server) cursor = conn.cursor() cursor.execute("INSERT OR REPLACE INTO seen(name, date, quote, chan)" - "values(?,?,?,?)", (input.nick.lower(), datetime.now(), + "values(?,?,?,?)", (input.nick.lower(), time.time(), input.msg, input.chan)) conn.commit() - conn.close() @hook.command @@ -45,8 +30,7 @@ def seen(bot, input): if query.lower() == input.nick.lower(): return "Have you looked in a mirror lately?" - dbpath = os.path.join(bot.persist_dir, dbname) - conn = dbconnect(dbpath) + conn = db_connect(bot, input.server) cursor = conn.cursor() command = "SELECT date, quote FROM seen WHERE name LIKE ? AND chan = ?" \ @@ -54,19 +38,17 @@ def seen(bot, input): cursor.execute(command, (query, input.chan)) results = cursor.fetchone() - conn.close() - - if(results != None): - reltime = timesince.timesince(datetime.fromtimestamp(results[0])) + if results: + reltime = timesince.timesince(results[0]) return '%s was last seen %s ago saying: %s' % \ (query, reltime, results[1]) else: return "I've never seen %s" % query -def dbconnect(db): +def db_connect(bot, server): "check to see that our db has the the seen table and return a connection." - conn = sqlite3.connect(db) + conn = bot.get_db_connection(server) conn.execute("CREATE TABLE IF NOT EXISTS " "seen(name varchar(30) not null, date datetime not null, " diff --git a/plugins/tell.py b/plugins/tell.py index 6aea6fc..48d770c 100644 --- a/plugins/tell.py +++ b/plugins/tell.py @@ -1,131 +1,100 @@ " tell.py: written by sklnd in July 2009" +" 2010.01.25 - modified by Scaevolus" -import os -import time -from datetime import datetime import sqlite3 +import time from util import hook, timesince - -dbname = "skybot.db" +def get_tells(conn, user_to, chan): + return conn.execute("select user_from, message, time from tell where" + " user_to=lower(?) and chan=? order by time", + (user_to.lower(), chan)).fetchall() -def adapt_datetime(ts): - return time.mktime(ts.timetuple()) - -sqlite3.register_adapter(datetime, adapt_datetime) - - -@hook.command(hook=r'^(?!\.showtells)(.*)', prefix=False, ignorebots=True) +@hook.command(hook=r'(.*)', prefix=False) def tellinput(bot, input): - dbpath = os.path.join(bot.persist_dir, dbname) - conn = dbconnect(dbpath) + if 'showtells' in input.inp.lower(): + return + + conn = db_connect(bot, input.server) - cursor = conn.cursor() - command = "select count(name) from tell where name LIKE ? and chan = ?" - results = cursor.execute(command, (input.nick, input.chan)).fetchone() + tells = get_tells(conn, input.nick, input.chan) + if tells: + user_from, message, time = tells[0] + reltime = timesince.timesince(time) - if results[0] > 0: - command = "select id, user_from, quote, date from tell " \ - "where name LIKE ? and chan = ? limit 1" - tell = cursor.execute(command, (input.nick, input.chan)).fetchall()[0] - more = results[0] - 1 - reltime = timesince.timesince(datetime.fromtimestamp(tell[3])) + reply = "%s said %s ago: %s" % (user_from, reltime, message) + if len(tells) > 1: + reply += " (+%d more, .showtells to view)" % (len(tells) - 1) - reply = "%(teller)s said %(reltime)s ago: %(quote)s" % \ - {"teller": tell[1], "quote": tell[2], "reltime": reltime} - if more: - reply += " (+%(more)d more, to view use .showtells)" % {"more": more} - - input.reply(reply) - command = "delete from tell where id = ?" - cursor.execute(command, (tell[0], )) - + conn.execute("delete from tell where user_to=lower(?) and message=?", + (input.nick, message)) conn.commit() - conn.close() + return reply @hook.command def showtells(bot, input): ".showtells -- view all pending tell messages (sent in PM)." - dbpath = os.path.join(bot.persist_dir, dbname) - conn = dbconnect(dbpath) + conn = db_connect(bot, input.server) - cursor = conn.cursor() - command = "SELECT id, user_from, quote, date FROM tell " \ - "WHERE name LIKE ? and chan = ?" - tells = cursor.execute(command, (input.nick, input.chan)).fetchall() + tells = get_tells(conn, input.nick, input.chan) - if(len(tells) > 0): - for tell in tells: - reltime = timesince.timesince(datetime.fromtimestamp(tell[3])) - input.pm('%(teller)s said %(time)s ago: %(quote)s' % \ - {'teller': tell[1], 'quote': tell[2], 'time': reltime}) - - command = "delete from tell where id = ?" - cursor.execute(command, (tell[0], )) - - conn.commit() - else: + if not tells: input.pm("You have no pending tells.") - - conn.close() + return + for tell in tells: + user_from, message, time = tell + reltime = timesince.timesince(time) + input.pm("%s said %s ago: %s" % (user_from, reltime, message)) + + conn.execute("delete from tell where user_to=lower(?) and chan=?", + (input.nick, input.chan)) + conn.commit() @hook.command def tell(bot, input): ".tell -- relay to when is around" - if len(input.msg) < 6: + query = input.inp.split(' ', 1) + + if len(query) != 2 or not input.inp: return tell.__doc__ - query = input.inp.partition(" ") - - if query[0] == input.nick: + user_to = query[0].lower() + message = query[1].strip() + user_from = input.nick + + if user_to == user_from.lower(): return "No." + conn = db_connect(bot, input.server) - if query[2] != "": - dbpath = os.path.join(bot.persist_dir, dbname) - conn = dbconnect(dbpath) - - command = "select count(*) from tell_probation where name=? and chan=?" - if conn.execute(command, (input.nick, input.chan)).fetchone()[0] > 0: - return "No." - - command = "select count(*) from tell where name=? and user_from=?" - if conn.execute(command, (query[0], input.nick)).fetchone()[0] >= 3: - return "You've told that person too many things." - - cursor = conn.cursor() - command = "insert into tell(name, user_from, quote, chan, date) " \ - "values(?,?,?,?,?)" - cursor.execute(command, (query[0], input.nick, query[2], input.chan, - datetime.now())) + if conn.execute("select count() from tell where user_to=?", + (user_to,)).fetchone()[0] >= 5: + return "That person has too many things queued." + try: + conn.execute("insert into tell(user_to, user_from, message, chan," + "time) values(?,?,?,?,?)", (user_to, user_from, message, + input.chan, time.time())) conn.commit() - conn.close() - return "I'll pass that along." + except sqlite3.IntegrityError: + return "Message has already been queued." - else: - return tell.__doc__ + return "I'll pass that along." -def dbconnect(db): +def db_connect(bot, server): "check to see that our db has the tell table and return a connection." - conn = sqlite3.connect(db) - - conn.execute("CREATE TABLE IF NOT EXISTS tell(id integer primary key " - "autoincrement, name text not null, user_from text not null," - "quote text not null, chan text not null, " - "date datetime not null);") - - conn.execute("CREATE TABLE IF NOT EXISTS " - "tell_probation(name text, chan text," - "primary key(name, chan));") + conn = bot.get_db_connection(server) + conn.execute("create table if not exists tell" + "(user_to, user_from, message, chan, time," + "primary key(user_to, message))") conn.commit() - + return conn diff --git a/plugins/urlhistory.py b/plugins/urlhistory.py index 2988659..c16f27a 100644 --- a/plugins/urlhistory.py +++ b/plugins/urlhistory.py @@ -1,39 +1,34 @@ -import os import time -import sqlite3 -import pickle import re from util import hook, urlnorm url_re = re.compile(r'([a-zA-Z]+://|www\.)[^ ]*') -dbname = "skybot.db" - expiration_period = 60 * 60 * 24 # 1 day expiration_period_text = "24 hours" ignored_urls = [urlnorm.normalize("http://google.com")] -def dbconnect(db): +def db_connect(bot, server): "check to see that our db has the the seen table and return a connection." - conn = sqlite3.connect(db) + conn = bot.get_db_connection(server) conn.execute("create table if not exists urlhistory" - "(server, chan, url, nick, time)") + "(chan, url, nick, time)") conn.commit() return conn -def insert_history(conn, server, chan, url, nick): +def insert_history(conn, chan, url, nick): now = time.time() - conn.execute("insert into urlhistory(server, chan, url, nick, time) " - "values(?,?,?,?,?)", (server, chan, url, nick, time.time())) + conn.execute("insert into urlhistory(chan, url, nick, time) " + "values(?,?,?,?)", (chan, url, nick, time.time())) conn.commit() -def get_history(conn, server, chan, url): +def get_history(conn, chan, url): conn.execute("delete from urlhistory where time < ?", (time.time() - expiration_period,)) - nicks = conn.execute("select nick from urlhistory where server=? " - "and chan=? and url=?", (server, chan, url)).fetchall() + nicks = conn.execute("select nick from urlhistory where " + "chan=? and url=?", (chan, url)).fetchall() return [x[0] for x in nicks] def get_nicklist(nicks): @@ -48,18 +43,17 @@ def ordinal(count): @hook.command(hook=r'(.*)', prefix=False) def urlinput(bot, input): - dbpath = os.path.join(bot.persist_dir, dbname) m = url_re.search(input.msg.encode('utf8')) if not m: return # URL detected - conn = dbconnect(dbpath) + conn = db_connect(bot, input.server) try: url = urlnorm.normalize(m.group(0)) if url not in ignored_urls: - dupes = get_history(conn, input.server, input.chan, url) - insert_history(conn, input.server, input.chan, url, input.nick) + dupes = get_history(conn, input.chan, url) + insert_history(conn, input.chan, url, input.nick) if dupes and input.nick not in dupes: input.reply("That link has been posted " + ordinal(len(dupes)) + " in the past " + expiration_period_text + " by " + diff --git a/plugins/util/timesince.py b/plugins/util/timesince.py index 03e8802..a9488d2 100644 --- a/plugins/util/timesince.py +++ b/plugins/util/timesince.py @@ -50,6 +50,9 @@ def timesince(d, now=None): (60 * 60, ('hour', 'hours')), (60, ('minute', 'minutes')) ) + if isinstance(d, int) or isinstance(d, float): + d = datetime.datetime.fromtimestamp(d) + # Convert datetime.date to datetime.datetime for comparison. if not isinstance(d, datetime.datetime): d = datetime.datetime(d.year, d.month, d.day) diff --git a/plugins/wolframalpha.py b/plugins/wolframalpha.py index c85542c..93292ab 100644 --- a/plugins/wolframalpha.py +++ b/plugins/wolframalpha.py @@ -12,7 +12,7 @@ def wolframalpha(inp): "results for " if not inp: - return wolframalpha.__help__ + return wolframalpha.__doc__ url = "http://www.wolframalpha.com/input/?i=%s&asynchronous=false"