convert to a MySQL backend
WARNING! there's no going back now. this change is *huge* but it was overdue. WARNING! the database backend is now mysql. modules that should use a database but don't yet were left untouched, they'll come later. scripts haven't been converted yet, though i'm pretty sure i'll need to soon. while i was going through everything, connection/cursor idioms were cleaned up, as were a bunch of log messages and exception handling. this change is so gross i'm happy things appear to be working, which is the case --- all modules are lightly tested.
This commit is contained in:
parent
deedf330e3
commit
1a36becead
50
Module.py
50
Module.py
@ -21,9 +21,10 @@ from ConfigParser import NoSectionError, NoOptionError
|
||||
import logging
|
||||
import re
|
||||
import sys
|
||||
import sqlite3
|
||||
from threading import Timer
|
||||
|
||||
import MySQLdb as mdb
|
||||
|
||||
from extlib import irclib
|
||||
|
||||
class Module(object):
|
||||
@ -165,7 +166,7 @@ class Module(object):
|
||||
|
||||
def get_db(self):
|
||||
"""
|
||||
Get a database connection to sqlite3. Once grabbed, it should be closed
|
||||
Get a database connection to mdb. Once grabbed, it should be closed
|
||||
when work is done. Modules that need a database connection should
|
||||
test for and create (or, eventually, alter) required table structure
|
||||
in their __init__ IF that structure does not already exist. Well-behaved
|
||||
@ -175,17 +176,13 @@ class Module(object):
|
||||
See also db_module_registered, below.
|
||||
"""
|
||||
|
||||
dbfile = self.config.get('dr.botzo', 'database')
|
||||
conn = sqlite3.connect(dbfile, isolation_level=None)
|
||||
conn.row_factory = sqlite3.Row
|
||||
dbhost = self.config.get('dr.botzo', 'dbhost')
|
||||
dbuser = self.config.get('dr.botzo', 'dbuser')
|
||||
dbpass = self.config.get('dr.botzo', 'dbpass')
|
||||
dbname = self.config.get('dr.botzo', 'dbname')
|
||||
db = mdb.connect(dbhost, dbuser, dbpass, dbname, use_unicode=True)
|
||||
|
||||
# setup regexp function in sqlite
|
||||
def regexp(expr, item):
|
||||
reg = re.compile(expr, re.IGNORECASE)
|
||||
return reg.search(item) is not None
|
||||
conn.create_function('REGEXP', 2, regexp)
|
||||
|
||||
return conn
|
||||
return db
|
||||
|
||||
def db_module_registered(self, modulename):
|
||||
"""
|
||||
@ -193,19 +190,20 @@ class Module(object):
|
||||
number if the module has registered, or None if not
|
||||
"""
|
||||
|
||||
conn = self.get_db()
|
||||
db = self.get_db()
|
||||
version = None
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT version FROM drbotzo_modules WHERE module = :name",
|
||||
{'name': modulename})
|
||||
cur = db.cursor()
|
||||
cur.execute("SELECT version FROM drbotzo_modules WHERE module = %s",
|
||||
(modulename,))
|
||||
version = cur.fetchone()
|
||||
if (version != None):
|
||||
version = version[0]
|
||||
conn.close()
|
||||
except sqlite3.Error as e:
|
||||
conn.close()
|
||||
self.log.error("sqlite error:" + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during module registered check")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
return version
|
||||
|
||||
@ -214,14 +212,16 @@ class Module(object):
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db.execute('INSERT OR REPLACE INTO drbotzo_modules (version, module) VALUES (?, ?)', (version, modulename))
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute('INSERT IGNORE INTO drbotzo_modules (version, module) VALUES (%s, %s)',
|
||||
(version, modulename))
|
||||
db.commit()
|
||||
db.close()
|
||||
except sqlite3.Error as e:
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
self.log.error("database error during register module version")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def db_init(self):
|
||||
"""
|
||||
|
@ -7,10 +7,13 @@ usermode = -x
|
||||
debug = true
|
||||
admin_userhost = bss@ayu.incorporeal.org
|
||||
module_list = IrcAdmin
|
||||
database = dr.botzo.data
|
||||
dbhost = localhost
|
||||
dbuser = dr_botzo
|
||||
dbpass = password
|
||||
dbname = dr_botzo
|
||||
|
||||
[IrcAdmin]
|
||||
autojoin = #bss
|
||||
|
||||
[Karma]
|
||||
meta.pubmsg_needs_bot_prefix = false
|
||||
meta.pubmsg_needs_bot_prefix = false
|
||||
|
38
dr.botzo.py
38
dr.botzo.py
@ -21,7 +21,8 @@ import logging
|
||||
import logging.config
|
||||
import os
|
||||
import sys
|
||||
import sqlite3
|
||||
|
||||
import MySQLdb as mdb
|
||||
|
||||
import DrBotIRC
|
||||
from extlib import irclib
|
||||
@ -53,28 +54,31 @@ logging.config.fileConfig('logging.cfg')
|
||||
log = logging.getLogger('drbotzo')
|
||||
|
||||
try:
|
||||
# make sure we can initialize the database, if such a thing is
|
||||
# called for in the config file
|
||||
dbfile = config.get('dr.botzo', 'database')
|
||||
conn = sqlite3.connect(dbfile, isolation_level=None)
|
||||
dbhost = config.get('dr.botzo', 'dbhost')
|
||||
dbuser = config.get('dr.botzo', 'dbuser')
|
||||
dbpass = config.get('dr.botzo', 'dbpass')
|
||||
dbname = config.get('dr.botzo', 'dbname')
|
||||
db = mdb.connect(dbhost, dbuser, dbpass, dbname, use_unicode=True)
|
||||
try:
|
||||
cur = db.cursor()
|
||||
# need to create the drbotzo_modules table if it doesn't exist
|
||||
query = """
|
||||
SELECT COUNT(*)
|
||||
FROM sqlite_master
|
||||
WHERE type = 'table' AND name = 'drbotzo_modules'
|
||||
SELECT COUNT(*) FROM information_schema.tables
|
||||
WHERE table_schema = %s
|
||||
AND table_name = %s
|
||||
"""
|
||||
row = conn.execute(query).fetchone()
|
||||
cur.execute(query, (dbname, 'drbotzo_modules'))
|
||||
row = cur.fetchone()
|
||||
if row[0] == 0:
|
||||
# need to create the drbotzo_modules table
|
||||
query = """
|
||||
CREATE TABLE drbotzo_modules (
|
||||
module TEXT PRIMARY KEY,
|
||||
version INTEGER
|
||||
)
|
||||
CREATE TABLE IF NOT EXISTS drbotzo_modules (
|
||||
module VARCHAR(64) PRIMARY KEY,
|
||||
version INTEGER
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
"""
|
||||
conn.execute(query)
|
||||
conn.commit()
|
||||
finally: conn.close()
|
||||
cur.execute(query)
|
||||
db.commit()
|
||||
finally: cur.close()
|
||||
except NoOptionError as e:
|
||||
sys.exit("Aborted due to error with necessary configuration: " + str(e))
|
||||
|
||||
|
@ -17,10 +17,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sqlite3
|
||||
import thread
|
||||
import time
|
||||
|
||||
import MySQLdb as mdb
|
||||
|
||||
from Module import Module
|
||||
|
||||
from extlib import irclib
|
||||
@ -73,89 +74,73 @@ class Achievements(Module):
|
||||
db = self.get_db()
|
||||
try:
|
||||
version = 1
|
||||
db.execute('''
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute('''
|
||||
CREATE TABLE achievements_player (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
nick TEXT NOT NULL UNIQUE,
|
||||
userhost TEXT NOT NULL DEFAULT '',
|
||||
id SERIAL,
|
||||
nick VARCHAR(64) NOT NULL UNIQUE,
|
||||
userhost VARCHAR(256) NOT NULL DEFAULT '',
|
||||
is_playing INTEGER NOT NULL DEFAULT 0,
|
||||
last_seen_time TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)''')
|
||||
db.execute('''
|
||||
last_seen_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
CREATE TABLE achievements_event (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
player_id INTEGER NOT NULL,
|
||||
event TEXT NOT NULL,
|
||||
target TEXT,
|
||||
id SERIAL,
|
||||
player_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
event VARCHAR(64) NOT NULL,
|
||||
target VARCHAR(64),
|
||||
msg_len INTEGER,
|
||||
event_time TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
event_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY(player_id) REFERENCES achievements_player(id)
|
||||
)''')
|
||||
db.execute('''
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
CREATE TABLE achievements_achievement (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
desc TEXT NOT NULL,
|
||||
query TEXT NOT NULL
|
||||
)''')
|
||||
db.execute('''
|
||||
id SERIAL,
|
||||
name VARCHAR(256) NOT NULL,
|
||||
description VARCHAR(256) NOT NULL,
|
||||
query VARCHAR(1024) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
CREATE TABLE achievements_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
player_id INTEGER NOT NULL,
|
||||
achievement_id INTEGER NOT NULL,
|
||||
event_time TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
id SERIAL,
|
||||
player_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
achievement_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
event_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY(player_id) REFERENCES achievements_player(id),
|
||||
FOREIGN KEY(achievement_id) REFERENCES achievements_achievement(id)
|
||||
)''')
|
||||
db.commit()
|
||||
db.close()
|
||||
self.db_register_module_version(self.__class__.__name__, version)
|
||||
except sqlite3.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
raise
|
||||
if (version < 2):
|
||||
db = self.get_db()
|
||||
try:
|
||||
version = 2
|
||||
db.execute('''
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
CREATE TABLE achievements_config (
|
||||
channel TEXT NOT NULL
|
||||
)''')
|
||||
db.commit()
|
||||
db.close()
|
||||
self.db_register_module_version(self.__class__.__name__, version)
|
||||
except sqlite3.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
raise
|
||||
if (version < 3):
|
||||
db = self.get_db()
|
||||
try:
|
||||
version = 3
|
||||
db.execute('''
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
CREATE TABLE achievements_filter (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
filter TEXT NOT NULL
|
||||
)''')
|
||||
db.execute('''
|
||||
id SERIAL,
|
||||
filter VARCHAR(256) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
CREATE TABLE achievements_filter_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
filter_id INTEGER NOT NULL,
|
||||
event_id INTEGER NOT NULL,
|
||||
id SERIAL,
|
||||
filter_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
event_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
FOREIGN KEY(filter_id) REFERENCES achievements_filter(id),
|
||||
FOREIGN KEY(event_id) REFERENCES achievements_event(id)
|
||||
)''')
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
db.commit()
|
||||
db.close()
|
||||
self.db_register_module_version(self.__class__.__name__, version)
|
||||
except sqlite3.Error as e:
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
self.log.error("database error trying to create tables")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def register_handlers(self):
|
||||
"""Handle all sorts of things to track."""
|
||||
@ -247,37 +232,37 @@ class Achievements(Module):
|
||||
def _get_or_add_player(self, nick, userhost):
|
||||
"""Add a player to the database, or update the existing one, and return the id."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = '''
|
||||
INSERT OR IGNORE INTO achievements_player (nick) VALUES (?)'''
|
||||
INSERT IGNORE INTO achievements_player (nick) VALUES (%s)'''
|
||||
cur.execute(statement, (nick,))
|
||||
statement = '''
|
||||
UPDATE achievements_player SET userhost = ?, last_seen_time = CURRENT_TIMESTAMP
|
||||
WHERE nick = ?'''
|
||||
UPDATE achievements_player SET userhost = %s, last_seen_time = CURRENT_TIMESTAMP
|
||||
WHERE nick = %s'''
|
||||
cur.execute(statement, (userhost, nick))
|
||||
db.commit()
|
||||
statement = '''SELECT id FROM achievements_player WHERE nick = ?'''
|
||||
cur = db.execute(statement, (nick,))
|
||||
statement = '''SELECT id FROM achievements_player WHERE nick = %s'''
|
||||
cur.execute(statement, (nick,))
|
||||
result = cur.fetchone()
|
||||
db.close()
|
||||
return result['id']
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error getting or adding player")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _add_event(self, player_id, event, target, msg, msg_len):
|
||||
"""Add an event to the log."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = '''
|
||||
INSERT INTO achievements_event (
|
||||
player_id, event, target, msg_len
|
||||
) VALUES (?, ?, ?, ?)
|
||||
) VALUES (%s, %s, %s, %s)
|
||||
'''
|
||||
cur.execute(statement, (player_id, event, target, msg_len))
|
||||
db.commit()
|
||||
@ -285,135 +270,143 @@ class Achievements(Module):
|
||||
|
||||
# now see if the event matched any filters
|
||||
query = '''
|
||||
SELECT id FROM achievements_filter WHERE ? REGEXP filter
|
||||
SELECT id FROM achievements_filter WHERE %s REGEXP filter
|
||||
'''
|
||||
cursor = db.execute(query, (msg.decode('utf-8', 'replace'),))
|
||||
results = cursor.fetchall()
|
||||
cur.execute(query, (msg.decode('utf-8', 'replace'),))
|
||||
results = cur.fetchall()
|
||||
for result in results:
|
||||
cur = db.cursor()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = '''
|
||||
INSERT INTO achievements_filter_log (filter_id, event_id)
|
||||
VALUES (?, ?)
|
||||
VALUES (%s, %s)
|
||||
'''
|
||||
cur.execute(statement, (result['id'], event_id))
|
||||
db.commit()
|
||||
|
||||
db.close()
|
||||
|
||||
return event_id
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error adding event")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_achievements_settings(self):
|
||||
"""Get the report settings."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
# get the settings
|
||||
db = self.get_db()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = 'SELECT channel FROM achievements_config'
|
||||
cursor = db.execute(query)
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur.execute(query)
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
settings = self.AchievementsSettings()
|
||||
settings.channel = result['channel']
|
||||
|
||||
return settings
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
else:
|
||||
return None
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error getting settings")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
except AttributeError as e:
|
||||
self.log.error("could not get channel settings, probably unset")
|
||||
self.log.exception(e)
|
||||
return None
|
||||
finally: cur.close()
|
||||
|
||||
def _join_system(self, nick):
|
||||
"""Add the appropriate nick to the game."""
|
||||
"""Add the appropriate nick to the system."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
statement = 'UPDATE achievements_player SET is_playing = 1 WHERE nick = ?'
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = 'UPDATE achievements_player SET is_playing = 1 WHERE nick = %s'
|
||||
cur.execute(statement, (nick,))
|
||||
db.commit()
|
||||
db.close()
|
||||
return nick + ' joined.'
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error joining the system")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _leave_system(self, nick):
|
||||
"""Remove the appropriate nick from the game."""
|
||||
"""Remove the appropriate nick from the system."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
statement = 'UPDATE achievements_player SET is_playing = 0 WHERE nick = ?'
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = 'UPDATE achievements_player SET is_playing = 0 WHERE nick = %s'
|
||||
cur.execute(statement, (nick,))
|
||||
db.commit()
|
||||
db.close()
|
||||
return nick + ' left.'
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error leaving the system")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _add_player_to_achievement_log(self, player_id, achievement_id):
|
||||
"""Log the success of a player."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
statement = 'INSERT INTO achievements_log (player_id, achievement_id) VALUES (?, ?)'
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = 'INSERT INTO achievements_log (player_id, achievement_id) VALUES (%s, %s)'
|
||||
cur.execute(statement, (player_id, achievement_id))
|
||||
db.commit()
|
||||
db.close()
|
||||
return
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error adding player to achievement log")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_achievement_info(self, achievement):
|
||||
"""Return the description of a given achievement."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
query = 'SELECT desc FROM achievements_achievement WHERE name = ?'
|
||||
cursor = db.execute(query, (achievement,))
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = 'SELECT description FROM achievements_achievement WHERE name = %s'
|
||||
cur.execute(query, (achievement,))
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
return result['desc']
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
return result['description']
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error getting achievement info")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_player_achievements(self, nick):
|
||||
"""Return the achievements the nick has."""
|
||||
|
||||
achievements = []
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = '''
|
||||
SELECT a.name FROM achievements_achievement a
|
||||
INNER JOIN achievements_log l ON l.achievement_id = a.id
|
||||
INNER JOIN achievements_player p ON p.id = l.player_id
|
||||
WHERE p.nick = ?
|
||||
WHERE p.nick = %s
|
||||
'''
|
||||
cursor = db.execute(query, (nick,))
|
||||
results = cursor.fetchall()
|
||||
db.close()
|
||||
cur.execute(query, (nick,))
|
||||
results = cur.fetchall()
|
||||
for result in results:
|
||||
achievements.append(result['name'])
|
||||
|
||||
return achievements
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error getting player achievements")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _do_achievement_scan(self):
|
||||
"""Run the queries in the database, seeing if anyone new has an achievement."""
|
||||
@ -428,22 +421,26 @@ class Achievements(Module):
|
||||
if self.connection is None:
|
||||
return
|
||||
|
||||
self.log.debug('in achievement scan')
|
||||
settings = self._get_achievements_settings()
|
||||
channel = settings.channel
|
||||
achievers = self._query_for_new_achievers()
|
||||
for achiever in achievers:
|
||||
self.sendmsg(self.connection, channel, achiever[0] + ' achieved ' + achiever[1] + '!')
|
||||
if settings is not None:
|
||||
channel = settings.channel
|
||||
achievers = self._query_for_new_achievers()
|
||||
for achiever in achievers:
|
||||
self.sendmsg(self.connection, channel, achiever[0] + ' achieved ' + achiever[1] + '!')
|
||||
|
||||
def _query_for_new_achievers(self):
|
||||
"""Get new achievement earners for each achievement."""
|
||||
|
||||
achievers = []
|
||||
self.log.debug('checking achievements')
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = 'SELECT id, name, query FROM achievements_achievement'
|
||||
cursor = db.execute(query)
|
||||
achievements = cursor.fetchall()
|
||||
cur.execute(query)
|
||||
achievements = cur.fetchall()
|
||||
|
||||
for achievement in achievements:
|
||||
self.log.debug('checking achievement:[' + achievement['name'] + ']')
|
||||
@ -458,22 +455,22 @@ class Achievements(Module):
|
||||
SELECT player_id FROM achievements_log l
|
||||
INNER JOIN achievements_achievement a
|
||||
ON a.id = l.achievement_id
|
||||
WHERE a.name = ?
|
||||
WHERE a.name = %s
|
||||
)
|
||||
'''
|
||||
cursor = db.execute(query, (achievement['name'],))
|
||||
ach_achievers = cursor.fetchall()
|
||||
cur.execute(query, (achievement['name'],))
|
||||
ach_achievers = cur.fetchall()
|
||||
|
||||
for ach_achiever in ach_achievers:
|
||||
self.log.debug('name:[' + ach_achiever['nick'] + '] achievement:[' + achievement['name'] + ']')
|
||||
self._add_player_to_achievement_log(ach_achiever['id'], achievement['id'])
|
||||
achievers.append((ach_achiever['nick'], achievement['name']))
|
||||
|
||||
db.close()
|
||||
return achievers
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error scanning new achievers")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
# vi:tabstop=4:expandtab:autoindent
|
||||
|
@ -18,7 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import random
|
||||
import re
|
||||
import sqlite3
|
||||
import thread
|
||||
import time
|
||||
|
||||
|
@ -18,7 +18,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import random
|
||||
import re
|
||||
import sqlite3
|
||||
|
||||
import MySQLdb as mdb
|
||||
|
||||
from extlib import irclib
|
||||
|
||||
@ -46,38 +47,40 @@ class Facts(Module):
|
||||
if version == None:
|
||||
db = self.get_db()
|
||||
try:
|
||||
db.execute('''
|
||||
version = 1
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute('''
|
||||
CREATE TABLE facts_facts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
category TEXT NOT NULL,
|
||||
fact TEXT NOT NULL,
|
||||
who TEXT NOT NULL,
|
||||
userhost TEXT NOT NULL,
|
||||
time TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
id SERIAL,
|
||||
category VARCHAR(64) NOT NULL,
|
||||
fact LONGTEXT NOT NULL,
|
||||
who VARCHAR(64) NOT NULL,
|
||||
userhost VARCHAR(256) NOT NULL,
|
||||
time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
db.execute('INSERT INTO drbotzo_modules VALUES (?,?)', (self.__class__.__name__, 1))
|
||||
db.commit()
|
||||
db.close()
|
||||
except sqlite3.Error as e:
|
||||
self.db_register_module_version(self.__class__.__name__, version)
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
self.log.error("database error trying to create tables")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def do(self, connection, event, nick, userhost, what, admin_unlocked):
|
||||
"""Add or retrieve a fact from the database."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
|
||||
match = re.search('^!facts\s+add\s+(\S+)\s+(.*)$', what)
|
||||
if match:
|
||||
category = match.group(1)
|
||||
fact = match.group(2)
|
||||
cur.execute('''INSERT INTO facts_facts (category, fact, who, userhost)
|
||||
VALUES (?, ?, ?, ?)''', (category, fact, nick, userhost))
|
||||
VALUES (%s, %s, %s, %s)''', (category, fact, nick, userhost))
|
||||
db.commit()
|
||||
return self.reply(connection, event, category + ' added.')
|
||||
|
||||
@ -91,10 +94,12 @@ class Facts(Module):
|
||||
if match:
|
||||
category = match.group(1)
|
||||
return self.reply(connection, event, self._get_fact(category))
|
||||
db.close()
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
return self.reply(connection, event, "sqlite error: " + str(e))
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
self.log.error("database error during add/retrieve")
|
||||
self.log.exception(e)
|
||||
return self.reply(connection, event, "database error during add/retrieve fact")
|
||||
finally: cur.close()
|
||||
|
||||
def _get_fact(self, category, search=""):
|
||||
"""
|
||||
@ -105,26 +110,27 @@ class Facts(Module):
|
||||
search - the optional regex to match against within that category
|
||||
"""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
|
||||
if search == "":
|
||||
category_facts = cur.execute("SELECT * FROM facts_facts WHERE category=?", (category,))
|
||||
facts = category_facts.fetchall()
|
||||
db.close()
|
||||
cur.execute("SELECT * FROM facts_facts WHERE category = %s",
|
||||
(category,))
|
||||
facts = cur.fetchall()
|
||||
else:
|
||||
category_facts = cur.execute("SELECT * FROM facts_facts WHERE category=? AND fact REGEXP ?",
|
||||
(category, search))
|
||||
facts = category_facts.fetchall()
|
||||
db.close()
|
||||
cur.execute("SELECT * FROM facts_facts WHERE category = %s AND fact REGEXP %s",
|
||||
(category, search))
|
||||
facts = cur.fetchall()
|
||||
|
||||
if len(facts) > 0:
|
||||
fact = facts[random.randint(1,len(facts))-1]
|
||||
return fact['fact'].rstrip().encode('utf-8', 'ignore')
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
return self.reply(connection, event, "sqlite error in _get_fact: " + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error in _get_fact")
|
||||
self.log.exception(e)
|
||||
return self.reply(connection, event, "database error in _get_fact")
|
||||
finally: cur.close()
|
||||
|
||||
# vi:tabstop=4:expandtab:autoindent
|
||||
# kate: indent-mode python;indent-width 4;replace-tabs on;
|
||||
|
@ -17,7 +17,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sqlite3
|
||||
|
||||
from Module import Module
|
||||
|
||||
|
180
modules/Karma.py
180
modules/Karma.py
@ -16,10 +16,12 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from math import floor
|
||||
import re
|
||||
import sqlite3
|
||||
import string
|
||||
|
||||
import MySQLdb as mdb
|
||||
|
||||
from Module import Module
|
||||
|
||||
__author__ = "Mike Bloy <mike@bloy.org>"
|
||||
@ -50,67 +52,40 @@ class Karma(Module):
|
||||
version = self.db_module_registered(self.__class__.__name__)
|
||||
if (version == None):
|
||||
# have to create the database tables
|
||||
conn = self.get_db()
|
||||
db = self.get_db()
|
||||
try:
|
||||
conn.execute('''
|
||||
CREATE TABLE karma_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
key TEXT NOT NULL,
|
||||
delta INTEGER NOT NULL,
|
||||
who TEXT NOT NULL,
|
||||
userhost TEXT NOT NULL,
|
||||
karmatime TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)''')
|
||||
conn.execute('CREATE INDEX karma_log_key_ix ON karma_log (key)')
|
||||
conn.execute('CREATE INDEX karma_log_who_ix ON karma_log (who)')
|
||||
conn.execute('''
|
||||
CREATE VIEW karma_values AS
|
||||
SELECT key, SUM(delta) AS value
|
||||
FROM karma_log
|
||||
GROUP BY key''')
|
||||
|
||||
sql = 'INSERT INTO drbotzo_modules VALUES (?,?)'
|
||||
conn.execute(sql, (self.__class__.__name__, 1))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
version = 1
|
||||
except sqlite3.Error as e:
|
||||
conn.rollback()
|
||||
conn.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
raise
|
||||
if (version < 2):
|
||||
conn = self.get_db()
|
||||
try:
|
||||
conn.execute('''
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute('''
|
||||
CREATE TABLE karma_log (
|
||||
id SERIAL,
|
||||
karma_key VARCHAR(128) NOT NULL,
|
||||
delta INTEGER NOT NULL,
|
||||
who VARCHAR(64) NOT NULL,
|
||||
userhost VARCHAR(256) NOT NULL,
|
||||
karmatime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('CREATE INDEX karma_log_key_ix ON karma_log (karma_key)')
|
||||
cur.execute('CREATE INDEX karma_log_who_ix ON karma_log (who)')
|
||||
cur.execute('''
|
||||
CREATE VIEW karma_values AS
|
||||
SELECT karma_key, SUM(delta) AS value
|
||||
FROM karma_log
|
||||
GROUP BY karma_key''')
|
||||
cur.execute('''
|
||||
CREATE VIEW karma_users AS
|
||||
SELECT who, COUNT(NULLIF(delta, -1)) AS pos,
|
||||
COUNT(NULLIF(delta, 1)) AS neg
|
||||
FROM karma_log GROUP BY who''')
|
||||
sql = 'UPDATE drbotzo_modules SET version = ? WHERE module = ?'
|
||||
conn.execute(sql, (2, self.__class__.__name__))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
version = 2
|
||||
except sqlite3.Error as e:
|
||||
conn.rollback()
|
||||
conn.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
raise
|
||||
if (version < 3):
|
||||
conn = self.get_db()
|
||||
try:
|
||||
version = 3
|
||||
conn.execute('''
|
||||
UPDATE karma_log SET key = LOWER(key)''')
|
||||
conn.commit()
|
||||
conn.close()
|
||||
db.commit()
|
||||
self.db_register_module_version(self.__class__.__name__, version)
|
||||
except sqlite3.Error as e:
|
||||
conn.rollback()
|
||||
conn.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
self.log.error("database error trying to create tables")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def do(self, connection, event, nick, userhost, what, admin_unlocked):
|
||||
"""look for karma strings at the start of messages"""
|
||||
@ -147,19 +122,21 @@ class Karma(Module):
|
||||
Go out to the database and update the karma value.
|
||||
"""
|
||||
|
||||
conn = self.get_db()
|
||||
db = self.get_db()
|
||||
try:
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
sql = '''
|
||||
INSERT INTO karma_log (key, delta, who, userhost)
|
||||
VALUES (?, ?, ?, ?)
|
||||
INSERT INTO karma_log (karma_key, delta, who, userhost)
|
||||
VALUES (%s, %s, %s, %s)
|
||||
'''
|
||||
conn.execute(sql, (key.decode('utf-8', 'ignore').lower(), value, nick, userhost))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
except sqlite3.Error as e:
|
||||
conn.rollback()
|
||||
conn.close()
|
||||
return "sqlite error: " + str(e)
|
||||
cur.execute(sql, (key.decode('utf-8', 'ignore').lower(), value, nick, userhost))
|
||||
db.commit()
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
self.log.error("database error modifying karma")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def handle_report_query(self, connection, nick, userhost, what):
|
||||
match = self.reportre.search(what)
|
||||
@ -169,61 +146,66 @@ class Karma(Module):
|
||||
query = None
|
||||
header = None
|
||||
if (report == 'highest'):
|
||||
query = 'SELECT key, value FROM karma_values ORDER BY value DESC LIMIT 5'
|
||||
query = 'SELECT karma_key AS who, value FROM karma_values ORDER BY value DESC LIMIT 5'
|
||||
header = 'Top 5 karma recipients:'
|
||||
elif (report == 'lowest'):
|
||||
query = 'SELECT key, value FROM karma_values ORDER BY value ASC LIMIT 5'
|
||||
query = 'SELECT karma_key AS who, value FROM karma_values ORDER BY value ASC LIMIT 5'
|
||||
header = 'Bottom 5 karma recipients:'
|
||||
elif (report == 'positive'):
|
||||
query = 'SELECT who, pos FROM karma_users ORDER BY pos DESC LIMIT 5'
|
||||
query = 'SELECT who, pos AS value FROM karma_users ORDER BY pos DESC LIMIT 5'
|
||||
header = 'Top 5 Optimists:'
|
||||
elif (report == 'negative'):
|
||||
query = 'SELECT who, neg FROM karma_users ORDER BY neg DESC LIMIT 5'
|
||||
query = 'SELECT who, neg AS value FROM karma_users ORDER BY neg DESC LIMIT 5'
|
||||
header = 'Top 5 Pessimists:'
|
||||
elif (report == 'top'):
|
||||
query = 'SELECT who, pos+neg AS total FROM karma_users ORDER BY total DESC LIMIT 5'
|
||||
query = 'SELECT who, pos+neg AS value FROM karma_users ORDER BY value DESC LIMIT 5'
|
||||
header = 'Top 5 Total Karma Givers:'
|
||||
|
||||
if (query != None):
|
||||
conn = self.get_db()
|
||||
db = self.get_db()
|
||||
list = []
|
||||
try:
|
||||
cursor = conn.execute(query)
|
||||
result = cursor.fetchone()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute(query)
|
||||
result = cur.fetchone()
|
||||
while (result != None):
|
||||
list.append("{key} ({value})".format(key=result[0], value=result[1]))
|
||||
result = cursor.fetchone()
|
||||
list.append("{key} ({value})".format(key=result['who'], value=result['value']))
|
||||
result = cur.fetchone()
|
||||
list = ', '.join(list)
|
||||
message = '{header} {list}'.format(header=header, list=list)
|
||||
conn.close()
|
||||
except sqlite3.Error as e:
|
||||
conn.rollback()
|
||||
conn.close()
|
||||
return "sqlite error: " + str(e)
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during report query")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
return message
|
||||
|
||||
def handle_stat_query(self, connection, nick, userhost, what):
|
||||
match = self.statre.search(what)
|
||||
statnick = match.group(1)
|
||||
|
||||
conn = self.get_db()
|
||||
db = self.get_db()
|
||||
reply = '{nick}: {statnick} has never given karma'.format(nick=nick, statnick=statnick)
|
||||
try:
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = '''
|
||||
SELECT pos, neg
|
||||
FROM karma_users
|
||||
WHERE who = :who
|
||||
'''
|
||||
value = conn.execute(query, {'who': statnick}).fetchone()
|
||||
cur.execute(query, {'who': statnick})
|
||||
value = cur.fetchone()
|
||||
if (value != None):
|
||||
pos = value[0]
|
||||
neg = value[1]
|
||||
total = pos+neg;
|
||||
reply = '{nick}: {statnick} has given {pos} postive karma and {neg} negative karma, for a total of {total} karma'.format(nick=nick, statnick=statnick, pos=pos, neg=neg, total=total)
|
||||
conn.close()
|
||||
except sqlite3.Error as e:
|
||||
conn.close()
|
||||
return "sqlite error: " + str(e)
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during handle stat query")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
return reply
|
||||
|
||||
@ -231,29 +213,33 @@ class Karma(Module):
|
||||
match = self.queryre.search(what)
|
||||
key = match.group(1)
|
||||
|
||||
conn = self.get_db()
|
||||
db = self.get_db()
|
||||
reply = '{nick}: {key} has no karma'.format(nick=nick, key=key)
|
||||
try:
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = '''
|
||||
SELECT value
|
||||
FROM karma_values
|
||||
WHERE key = :key
|
||||
WHERE karma_key = %s
|
||||
'''
|
||||
value = conn.execute(query, {'key': key.decode('utf-8', 'ignore').lower()}).fetchone()
|
||||
cur.execute(query, (key.decode('utf-8', 'ignore').lower(),))
|
||||
value = cur.fetchone()
|
||||
|
||||
if (value != None):
|
||||
query = '''
|
||||
SELECT count(*) FROM karma_values WHERE value > :value
|
||||
SELECT count(*) FROM karma_values WHERE value > %s
|
||||
'''
|
||||
rank = conn.execute(query, {'value': value[0]}).fetchone()
|
||||
rank = rank[0] + 1;
|
||||
cur.execute(query, (value['value'],))
|
||||
rank = cur.fetchone()
|
||||
rank = rank['count(*)'] + 1;
|
||||
|
||||
reply = '{nick}: {key} has {value[0]!s} points of karma (rank {rank})'.format(
|
||||
nick=nick, key=key, value=value, rank=rank)
|
||||
conn.close()
|
||||
except sqlite3.Error as e:
|
||||
conn.close()
|
||||
return "sqlite error: " + str(e)
|
||||
reply = '{0:s}: {1:s} has {2:d} points of karma (rank {3:d})'.format(
|
||||
nick, key, int(floor(value['value'])), rank)
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during handle karma query")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
return reply
|
||||
|
||||
|
@ -21,11 +21,12 @@ from datetime import datetime
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import sqlite3
|
||||
import sys
|
||||
import thread
|
||||
import time
|
||||
|
||||
import MySQLdb as mdb
|
||||
|
||||
from dateutil.parser import *
|
||||
from dateutil.relativedelta import *
|
||||
from extlib import irclib
|
||||
@ -76,67 +77,58 @@ class Markov(Module):
|
||||
"""Create the markov chain table."""
|
||||
|
||||
version = self.db_module_registered(self.__class__.__name__)
|
||||
if (version == None or version < 9):
|
||||
if version == None:
|
||||
db = self.get_db()
|
||||
try:
|
||||
version = 9
|
||||
|
||||
# recreating the tables, since i need to add some foreign key constraints
|
||||
db.execute('''DROP INDEX IF EXISTS markov_chain_keys_and_context_index''')
|
||||
db.execute('''DROP INDEX IF EXISTS markov_chain_keys_index''')
|
||||
db.execute('''DROP INDEX IF EXISTS markov_chain_value_and_context_index''')
|
||||
db.execute('''DROP TABLE IF EXISTS markov_chain''')
|
||||
db.execute('''DROP TABLE IF EXISTS markov_target_to_context_map''')
|
||||
db.execute('''DROP TABLE IF EXISTS markov_chatter_target''')
|
||||
db.execute('''DROP TABLE IF EXISTS markov_context''')
|
||||
|
||||
db.execute('''
|
||||
version = 1
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute('''
|
||||
CREATE TABLE markov_chatter_target (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
target TEXT NOT NULL,
|
||||
id SERIAL,
|
||||
target VARCHAR(256) NOT NULL,
|
||||
chance INTEGER NOT NULL DEFAULT 99999
|
||||
)''')
|
||||
|
||||
db.execute('''
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
CREATE TABLE markov_context (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
context TEXT NOT NULL
|
||||
)''')
|
||||
|
||||
db.execute('''
|
||||
id SERIAL,
|
||||
context VARCHAR(256) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
CREATE TABLE markov_target_to_context_map (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
target TEXT NOT NULL,
|
||||
context_id INTEGER NOT NULL,
|
||||
id SERIAL,
|
||||
target VARCHAR(256) NOT NULL,
|
||||
context_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
FOREIGN KEY(context_id) REFERENCES markov_context(id)
|
||||
)''')
|
||||
|
||||
db.execute('''
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
CREATE TABLE markov_chain (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
k1 TEXT NOT NULL,
|
||||
k2 TEXT NOT NULL,
|
||||
v TEXT NOT NULL,
|
||||
context_id INTEGER DEFAULT NULL,
|
||||
id SERIAL,
|
||||
k1 VARCHAR(128) NOT NULL,
|
||||
k2 VARCHAR(128) NOT NULL,
|
||||
v VARCHAR(128) NOT NULL,
|
||||
context_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
FOREIGN KEY(context_id) REFERENCES markov_context(id)
|
||||
)''')
|
||||
|
||||
db.execute('''
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
CREATE INDEX markov_chain_keys_and_context_id_index
|
||||
ON markov_chain (k1, k2, context_id)''')
|
||||
|
||||
db.execute('''
|
||||
cur.execute('''
|
||||
CREATE INDEX markov_chain_value_and_context_id_index
|
||||
ON markov_chain (v, context_id)''')
|
||||
|
||||
db.commit()
|
||||
db.close()
|
||||
self.db_register_module_version(self.__class__.__name__, version)
|
||||
except sqlite3.Error as e:
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
self.log.error("database error trying to create tables")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def register_handlers(self):
|
||||
"""Handle pubmsg/privmsg, to learn and/or reply to IRC events."""
|
||||
@ -303,10 +295,10 @@ class Markov(Module):
|
||||
if len(words) <= 0:
|
||||
return line
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
statement = 'INSERT INTO markov_chain (k1, k2, v, context_id) VALUES (?, ?, ?, ?)'
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = 'INSERT INTO markov_chain (k1, k2, v, context_id) VALUES (%s, %s, %s, %s)'
|
||||
for word in words:
|
||||
cur.execute(statement, (k1.decode('utf-8', 'replace'),
|
||||
k2.decode('utf-8', 'replace'), word.decode('utf-8', 'replace'), context_id))
|
||||
@ -315,12 +307,12 @@ class Markov(Module):
|
||||
k2.decode('utf-8', 'replace'), self.stop, context_id))
|
||||
|
||||
db.commit()
|
||||
db.close()
|
||||
except sqlite3.Error as e:
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error in Markov._learn_line: " + str(e))
|
||||
self.log.error("database error learning line")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _generate_line(self, target, line='', min_size=15, max_size=100):
|
||||
"""
|
||||
@ -412,69 +404,73 @@ class Markov(Module):
|
||||
"""Get the value(s) for a given key (a pair of strings)."""
|
||||
|
||||
values = []
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
query = ''
|
||||
if k1 == self.start1 and k2 == self.start2:
|
||||
# hack. get a quasi-random start from the database, in
|
||||
# a faster fashion than selecting all starts
|
||||
max_id = self._get_max_chain_id()
|
||||
rand_id = random.randint(1,max_id)
|
||||
query = ('SELECT v FROM markov_chain WHERE k1 = ? AND k2 = ? AND '
|
||||
'(context_id = ?) AND id >= {0:d} LIMIT 1'.format(rand_id))
|
||||
query = ('SELECT v FROM markov_chain WHERE k1 = %s AND k2 = %s AND '
|
||||
'(context_id = %s) AND id >= {0:d} LIMIT 1'.format(rand_id))
|
||||
else:
|
||||
query = ('SELECT v FROM markov_chain WHERE k1 = ? AND k2 = ? AND '
|
||||
'(context_id = ?)')
|
||||
cursor = db.execute(query, (k1.decode('utf-8', 'replace'),
|
||||
k2.decode('utf-8', 'replace'),
|
||||
context_id))
|
||||
results = cursor.fetchall()
|
||||
query = ('SELECT v FROM markov_chain WHERE k1 = %s AND k2 = %s AND '
|
||||
'(context_id = %s)')
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute(query, (k1.decode('utf-8', 'replace'),
|
||||
k2.decode('utf-8', 'replace'),
|
||||
context_id))
|
||||
results = cur.fetchall()
|
||||
|
||||
for result in results:
|
||||
values.append(result['v'].encode('utf-8', 'replace'))
|
||||
|
||||
db.close()
|
||||
return values
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error in Markov._retrieve_chains_for_key: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error in _retrieve_chains_for_key")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _retrieve_k2_for_value(self, v, context_id):
|
||||
"""Get the value(s) for a given key (a pair of strings)."""
|
||||
|
||||
values = []
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
query = 'SELECT k2 FROM markov_chain WHERE v = ? AND (context_id = ?)'
|
||||
cursor = db.execute(query, (v.decode('utf-8', 'replace'), context_id))
|
||||
results = cursor.fetchall()
|
||||
query = 'SELECT k2 FROM markov_chain WHERE v = %s AND context_id = %s'
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute(query, (v.decode('utf-8', 'replace'), context_id))
|
||||
results = cur.fetchall()
|
||||
|
||||
for result in results:
|
||||
values.append(result['k2'].encode('utf-8', 'replace'))
|
||||
|
||||
db.close()
|
||||
return values
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error in Markov._retrieve_k2_for_value: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error in _retrieve_k2_for_value")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_chatter_targets(self):
|
||||
"""Get all possible chatter targets."""
|
||||
|
||||
values = []
|
||||
db = self.get_db()
|
||||
try:
|
||||
# need to create our own db object, since this is likely going to be in a new thread
|
||||
db = self.get_db()
|
||||
query = 'SELECT target, chance FROM markov_chatter_target'
|
||||
cursor = db.execute(query)
|
||||
results = cursor.fetchall()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute(query)
|
||||
results = cur.fetchall()
|
||||
return results
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error in Markov._get_chatter_targets: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error in _get_chatter_targets")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_one_chatter_target(self):
|
||||
"""Select one random chatter target."""
|
||||
@ -486,37 +482,39 @@ class Markov(Module):
|
||||
def _get_max_chain_id(self):
|
||||
"""Get the highest id in the chain table."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
query = '''
|
||||
SELECT id FROM markov_chain ORDER BY id DESC LIMIT 1
|
||||
'''
|
||||
cursor = db.execute(query)
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute(query)
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
return result['id']
|
||||
else:
|
||||
return None
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error in Markov._get_max_chain_id: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error in _get_max_chain_id")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_context_id_for_target(self, target):
|
||||
|
||||
"""Get the context ID for the desired/input target."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
query = '''
|
||||
SELECT mc.id FROM markov_context mc
|
||||
INNER JOIN markov_target_to_context_map mt
|
||||
ON mt.context_id = mc.id
|
||||
WHERE mt.target = ?
|
||||
WHERE mt.target = %s
|
||||
'''
|
||||
cursor = db.execute(query, (target,))
|
||||
result = cursor.fetchone()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute(query, (target,))
|
||||
result = cur.fetchone()
|
||||
db.close()
|
||||
if result:
|
||||
return result['id']
|
||||
@ -524,53 +522,55 @@ class Markov(Module):
|
||||
# auto-generate a context to keep things private
|
||||
self._add_context_for_target(target)
|
||||
return self._get_context_id_for_target(target)
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error in Markov._get_context_id_for_target: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error in _get_context_id_for_target")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _add_context_for_target(self, target):
|
||||
|
||||
"""Create a new context for the desired/input target."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
statement = 'INSERT INTO markov_context (context) VALUES (?)'
|
||||
statement = 'INSERT INTO markov_context (context) VALUES (%s)'
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute(statement, (target,))
|
||||
statement = '''
|
||||
INSERT INTO markov_target_to_context_map (target, context_id)
|
||||
VALUES (?, (SELECT id FROM markov_context WHERE context = ?))
|
||||
VALUES (%s, (SELECT id FROM markov_context WHERE context = %s))
|
||||
'''
|
||||
cur.execute(statement, (target,target))
|
||||
db.commit()
|
||||
db.close()
|
||||
except sqlite3.Error as e:
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error in Markov._add_context_for_target: " + str(e))
|
||||
self.log.error("database error in _add_context_for_target")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
try:
|
||||
db = self.get_db()
|
||||
query = '''
|
||||
SELECT mc.id FROM markov_context mc
|
||||
INNER JOIN markov_target_to_context_map mt
|
||||
ON mt.context_id = mc.id
|
||||
WHERE mt.target = ?
|
||||
WHERE mt.target = %s
|
||||
'''
|
||||
cursor = db.execute(query, (target,))
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute(query, (target,))
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
return result['id']
|
||||
else:
|
||||
# auto-generate a context to keep things private
|
||||
self._add_context_for_target(target)
|
||||
return self._get_context_id_for_target(target)
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error in Markov._get_context_id_for_target: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error in _get_context_id_for_target")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
# vi:tabstop=4:expandtab:autoindent
|
||||
# kate: indent-mode python;indent-width 4;replace-tabs on;
|
||||
|
@ -19,7 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import math
|
||||
import random
|
||||
import re
|
||||
import sqlite3
|
||||
|
||||
import MySQLdb as mdb
|
||||
|
||||
from extlib import irclib
|
||||
|
||||
@ -46,37 +47,39 @@ class Pi(Module):
|
||||
# create tables
|
||||
db = self.get_db()
|
||||
try:
|
||||
db.execute('''
|
||||
version = 1
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute('''
|
||||
CREATE TABLE pi_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
id SERIAL,
|
||||
count_inside INTEGER NOT NULL,
|
||||
count_total INTEGER NOT NULL,
|
||||
time TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
db.execute('''
|
||||
cur.execute('''
|
||||
CREATE VIEW pi_latest_pi AS
|
||||
SELECT count_inside, count_total
|
||||
FROM pi_log
|
||||
ORDER BY id DESC
|
||||
''')
|
||||
db.execute('INSERT INTO drbotzo_modules VALUES (?,?)', (self.__class__.__name__, 1))
|
||||
db.commit()
|
||||
db.close()
|
||||
except sqlite3.Error as e:
|
||||
self.db_register_module_version(self.__class__.__name__, version)
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
self.log.error("database error trying to create tables")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def do(self, connection, event, nick, userhost, what, admin_unlocked):
|
||||
match = re.search('^!pi$', what)
|
||||
if match:
|
||||
db = self.get_db()
|
||||
try:
|
||||
cur = db.cursor()
|
||||
pi_data = cur.execute('SELECT * FROM pi_latest_pi')
|
||||
datum = pi_data.fetchone()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute('SELECT * FROM pi_latest_pi')
|
||||
datum = cur.fetchone()
|
||||
|
||||
if datum == None:
|
||||
count_inside = 0
|
||||
@ -96,13 +99,15 @@ class Pi(Module):
|
||||
count += 1
|
||||
pi = 4.0 * count_inside / count
|
||||
|
||||
cur.execute('INSERT INTO pi_log (count_inside, count_total) VALUES (?,?)', (count_inside, count))
|
||||
cur.execute('INSERT INTO pi_log (count_inside, count_total) VALUES (%s,%s)',
|
||||
(count_inside, count))
|
||||
db.commit()
|
||||
db.close()
|
||||
except sqlite3.Error as e:
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
return self.reply(connection, event, "sqlite error: " + str(e))
|
||||
self.log.error("database error doing pi stuff")
|
||||
self.log.exception(e)
|
||||
return self.reply(connection, event, "database error doing pi stuff")
|
||||
finally: cur.close()
|
||||
|
||||
return self.reply(connection, event, "({0:.10f}, {1:.10f}) is {2}within the circle. pi is {5:.10f}. (i:{3:d} p:{4:d})".format(x, y, "" if inside else "not ", count_inside, count, pi))
|
||||
|
||||
|
@ -17,7 +17,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sqlite3
|
||||
|
||||
import MySQLdb as mdb
|
||||
|
||||
from datetime import datetime
|
||||
from dateutil.tz import *
|
||||
@ -36,89 +37,72 @@ class Seen(Module):
|
||||
if version == None:
|
||||
db = self.get_db()
|
||||
try:
|
||||
db.execute('''
|
||||
CREATE TABLE seen_nicks (
|
||||
nick TEXT NOT NULL PRIMARY KEY,
|
||||
host TEXT NOT NULL,
|
||||
time TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
what TEXT NOT NULL
|
||||
)''')
|
||||
sql = 'INSERT INTO drbotzo_modules VALUES (?,?)'
|
||||
db.execute(sql, (self.__class__.__name__, 1))
|
||||
db.commit()
|
||||
db.close()
|
||||
version = 1
|
||||
except sqlite3.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
raise
|
||||
if version < 2:
|
||||
db = self.get_db()
|
||||
try:
|
||||
version = 2
|
||||
db.execute('''DROP TABLE seen_nicks''')
|
||||
db.execute('''
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute('''
|
||||
CREATE TABLE seen_nicks (
|
||||
nick TEXT NOT NULL,
|
||||
location TEXT NOT NULL,
|
||||
host TEXT NOT NULL,
|
||||
time TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
what TEXT NOT NULL
|
||||
)''')
|
||||
db.execute('''
|
||||
nick VARCHAR(64) NOT NULL PRIMARY KEY,
|
||||
location VARCHAR(64) NOT NULL,
|
||||
host VARCHAR(256) NOT NULL,
|
||||
time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
what LONGTEXT NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
CREATE UNIQUE INDEX seen_nicks_nick_and_location_index
|
||||
ON seen_nicks (nick, location)''')
|
||||
ON seen_nicks (nick, location)
|
||||
''')
|
||||
db.commit()
|
||||
db.close()
|
||||
self.db_register_module_version(self.__class__.__name__, version)
|
||||
except sqlite3.Error as e:
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
self.log.error("database error trying to create tables")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def do(self, connection, event, nick, userhost, what, admin_unlocked):
|
||||
"""Track pubmsg/privmsg events, and if asked, report on someone."""
|
||||
|
||||
where = event.target()
|
||||
|
||||
db = self.get_db()
|
||||
# whatever it is, store it
|
||||
try:
|
||||
# if there's no where, this is probably a sub-command. don't learn it
|
||||
if where:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
statement = 'REPLACE INTO seen_nicks (nick, location, host, what) VALUES (?, ?, ?, ?)'
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = 'REPLACE INTO seen_nicks (nick, location, host, what) VALUES (%s, %s, %s, %s)'
|
||||
cur.execute(statement, (nick, where, userhost, what.decode('utf-8', 'replace')))
|
||||
db.commit()
|
||||
db.close()
|
||||
except sqlite3.Error as e:
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
self.log.error("database error storing seen data")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
match = re.search('^!seen\s+(\S+)$', what)
|
||||
if match:
|
||||
nick = match.group(1)
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
query = 'SELECT * FROM seen_nicks WHERE nick = ? AND location = ?'
|
||||
cursor = db.execute(query, (nick,where))
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = 'SELECT * FROM seen_nicks WHERE nick = %s AND location = %s'
|
||||
cur.execute(query, (nick,where))
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
seentime = datetime.strptime(result['time'], '%Y-%m-%d %H:%M:%S').replace(tzinfo=tzutc())
|
||||
seentime = result['time'].replace(tzinfo=tzlocal())
|
||||
replystr = 'last saw {0:s} in {3:s} at {1:s} saying \'{2:s}\'.'.format(result['nick'], seentime.astimezone(tzlocal()).strftime('%Y/%m/%d %H:%M:%S %Z'), result['what'].encode('utf-8', 'ignore'), result['location'].encode('utf-8', 'ignore'))
|
||||
return self.reply(connection, event, replystr)
|
||||
else:
|
||||
return self.reply(connection, event, 'i have not seen {0:s} in {1:s}.'.format(nick, where))
|
||||
except sqlite3.Error as e:
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
self.log.error("database error retrieving seen data")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
# vi:tabstop=4:expandtab:autoindent
|
||||
# kate: indent-mode python;indent-width 4;replace-tabs on;
|
||||
|
@ -18,9 +18,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import random
|
||||
import re
|
||||
import sqlite3
|
||||
import time
|
||||
|
||||
import MySQLdb as mdb
|
||||
|
||||
from Module import Module
|
||||
|
||||
__author__ = "Brian S. Stephan"
|
||||
@ -101,66 +102,70 @@ class Storycraft(Module):
|
||||
# have to create the database tables
|
||||
db = self.get_db()
|
||||
try:
|
||||
db.execute('''
|
||||
version = 1
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute('''
|
||||
CREATE TABLE storycraft_config (
|
||||
master_channel TEXT NOT NULL,
|
||||
master_channel VARCHAR(64) NOT NULL,
|
||||
concurrent_games INTEGER NOT NULL,
|
||||
default_round_mode INTEGER NOT NULL,
|
||||
default_game_length INTEGER NOT NULL,
|
||||
default_line_length INTEGER NOT NULL,
|
||||
default_random_method INTEGER NOT NULL,
|
||||
default_lines_per_turn INTEGER NOT NULL
|
||||
)''')
|
||||
db.execute('''
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
INSERT INTO storycraft_config
|
||||
(master_channel, concurrent_games, default_round_mode,
|
||||
default_game_length, default_line_length,
|
||||
default_random_method, default_lines_per_turn)
|
||||
VALUES ('#drbotzo', 10, 1, 20, 140, 1, 2)
|
||||
VALUES ('#dr.botzo', 10, 1, 20, 140, 1, 2)
|
||||
''')
|
||||
db.execute('''
|
||||
cur.execute('''
|
||||
CREATE TABLE storycraft_game (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
id SERIAL,
|
||||
round_mode INTEGER NOT NULL,
|
||||
game_length INTEGER NOT NULL,
|
||||
line_length INTEGER NOT NULL,
|
||||
random_method INTEGER NOT NULL,
|
||||
lines_per_turn INTEGER NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
owner_nick TEXT NOT NULL,
|
||||
owner_userhost TEXT NOT NULL,
|
||||
start_time TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
end_time TEXT DEFAULT NULL
|
||||
)''')
|
||||
db.execute('''
|
||||
status VARCHAR(16) NOT NULL,
|
||||
owner_nick VARCHAR(64) NOT NULL,
|
||||
owner_userhost VARCHAR(256) NOT NULL,
|
||||
start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
end_time TIMESTAMP NULL DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
CREATE TABLE storycraft_player (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
game_id INTEGER NOT NULL,
|
||||
nick TEXT NOT NULL,
|
||||
userhost TEXT NOT NULL,
|
||||
id SERIAL,
|
||||
game_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
nick VARCHAR(64) NOT NULL,
|
||||
userhost VARCHAR(256) NOT NULL,
|
||||
FOREIGN KEY(game_id) REFERENCES storycraft_game(id)
|
||||
)''')
|
||||
db.execute('''
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
cur.execute('''
|
||||
CREATE TABLE storycraft_line (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
game_id INTEGER NOT NULL,
|
||||
player_id INTEGER NOT NULL,
|
||||
line TEXT NOT NULL,
|
||||
time TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY(game_id) REFERENCES storycraft_game(id)
|
||||
id SERIAL,
|
||||
game_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
player_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
line LONGTEXT NOT NULL,
|
||||
time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY(game_id) REFERENCES storycraft_game(id),
|
||||
FOREIGN KEY(player_id) REFERENCES storycraft_player(id)
|
||||
)''')
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
''')
|
||||
|
||||
sql = 'INSERT INTO drbotzo_modules VALUES (?,?)'
|
||||
db.execute(sql, (self.__class__.__name__, 1))
|
||||
db.commit()
|
||||
db.close()
|
||||
version = 1
|
||||
except sqlite3.Error as e:
|
||||
self.db_register_module_version(self.__class__.__name__, version)
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
self.log.error("database error trying to create tables")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def do(self, connection, event, nick, userhost, what, admin_unlocked):
|
||||
"""Pass storycraft control commands to the appropriate method based on input."""
|
||||
@ -525,18 +530,18 @@ class Storycraft(Module):
|
||||
def _get_game_details(self, game_id):
|
||||
"""Get the details of one game."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
# get the specified game and populate a StorycraftGame
|
||||
db = self.get_db()
|
||||
query = '''
|
||||
SELECT id, round_mode, game_length, line_length, random_method,
|
||||
lines_per_turn, status, owner_nick, owner_userhost, start_time,
|
||||
end_time
|
||||
FROM storycraft_game WHERE id = ?
|
||||
FROM storycraft_game WHERE id = %s
|
||||
'''
|
||||
cursor = db.execute(query, (game_id,))
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur.execute(query, (game_id,))
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
game = self.StorycraftGame()
|
||||
|
||||
@ -553,10 +558,11 @@ class Storycraft(Module):
|
||||
game.end_time = result['end_time']
|
||||
|
||||
return game
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during get game details")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_game_summary(self, game):
|
||||
"""Display game info for a general summary."""
|
||||
@ -601,35 +607,37 @@ class Storycraft(Module):
|
||||
def _add_new_game(self, round_mode, game_length, line_length, random_method, lines_per_turn, nick, userhost):
|
||||
"""Add a new game to the system."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = '''
|
||||
INSERT INTO storycraft_game (
|
||||
round_mode, game_length, line_length, random_method,
|
||||
lines_per_turn, status, owner_nick, owner_userhost
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||
'''
|
||||
cur.execute(statement, (round_mode, game_length, line_length, random_method, lines_per_turn, 'OPEN', nick, userhost))
|
||||
cur.execute(statement, (round_mode, game_length, line_length,
|
||||
random_method, lines_per_turn, 'OPEN', nick, userhost))
|
||||
db.commit()
|
||||
db.close()
|
||||
return cur.lastrowid
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
self.log.error("database error during add new game")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_player_list_for_game(self, game_id):
|
||||
"""Get the list of players in one game."""
|
||||
|
||||
players = []
|
||||
db = self.get_db()
|
||||
try:
|
||||
# get the players for specified game and populate a list
|
||||
db = self.get_db()
|
||||
query = 'SELECT id, game_id, nick, userhost FROM storycraft_player WHERE game_id = ?'
|
||||
cursor = db.execute(query, (game_id,))
|
||||
results = cursor.fetchall()
|
||||
db.close()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = 'SELECT id, game_id, nick, userhost FROM storycraft_player WHERE game_id = %s'
|
||||
cur.execute(query, (game_id,))
|
||||
results = cur.fetchall()
|
||||
for result in results:
|
||||
player = self.StorycraftPlayer()
|
||||
|
||||
@ -641,10 +649,11 @@ class Storycraft(Module):
|
||||
players.append(player)
|
||||
|
||||
return players
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during getting player list for game")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_game_exists(self, game_id):
|
||||
"""Return the existence of a game."""
|
||||
@ -654,20 +663,21 @@ class Storycraft(Module):
|
||||
def _start_game(self, game_id):
|
||||
"""Start a game, if it's currently open."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = '''
|
||||
UPDATE storycraft_game SET status = 'IN PROGRESS' WHERE status = 'OPEN' AND id = ?
|
||||
UPDATE storycraft_game SET status = 'IN PROGRESS' WHERE status = 'OPEN' AND id = %s
|
||||
'''
|
||||
cur.execute(statement, (game_id,))
|
||||
db.commit()
|
||||
db.close()
|
||||
return game_id
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
self.log.error("database error during start game")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _pick_next_player(self, game_id):
|
||||
"""Based on the game's settings and state, set who will be replying next."""
|
||||
@ -717,51 +727,53 @@ class Storycraft(Module):
|
||||
def _assign_game_to_player(self, game_id, player_id):
|
||||
"""Assign the game to a player, prompting them for responses."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = '''
|
||||
INSERT INTO storycraft_line (game_id, player_id, line)
|
||||
VALUES (?, ?, ?)
|
||||
VALUES (%s, %s, %s)
|
||||
'''
|
||||
cur.execute(statement, (game_id, player_id, ''))
|
||||
db.commit()
|
||||
db.close()
|
||||
return cur.lastrowid
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
self.log.error("database error during assign game to player")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _end_game(self, game_id):
|
||||
"""End the given game, disallowing adding lines."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = '''
|
||||
UPDATE storycraft_game SET status = 'COMPLETED', end_time = CURRENT_TIMESTAMP
|
||||
WHERE status = 'IN PROGRESS' AND id = ?
|
||||
WHERE status = 'IN PROGRESS' AND id = %s
|
||||
'''
|
||||
cur.execute(statement, (game_id,))
|
||||
db.commit()
|
||||
db.close()
|
||||
return game_id
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
self.log.error("database error during end game")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_player_by_id(self, player_id):
|
||||
"""Get the player details based on id."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
# get the specified player and populate a StorycraftPlayer
|
||||
db = self.get_db()
|
||||
query = 'SELECT id, game_id, nick, userhost FROM storycraft_player WHERE id = ?'
|
||||
cursor = db.execute(query, (player_id,))
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = 'SELECT id, game_id, nick, userhost FROM storycraft_player WHERE id = %s'
|
||||
cur.execute(query, (player_id,))
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
player = self.StorycraftPlayer()
|
||||
|
||||
@ -771,21 +783,22 @@ class Storycraft(Module):
|
||||
player.userhost = result['userhost']
|
||||
|
||||
return player
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during get player by id")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_player_by_userhost_in_game(self, game_id, userhost):
|
||||
"""Get the player details if they exist in the given game."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
# get the specified player if they exist in the game and populate a StorycraftPlayer
|
||||
db = self.get_db()
|
||||
query = 'SELECT id, game_id, nick, userhost FROM storycraft_player WHERE game_id = ? AND userhost = ?'
|
||||
cursor = db.execute(query, (game_id,userhost))
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = 'SELECT id, game_id, nick, userhost FROM storycraft_player WHERE game_id = %s AND userhost = %s'
|
||||
cur.execute(query, (game_id,userhost))
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
player = self.StorycraftPlayer()
|
||||
|
||||
@ -795,10 +808,11 @@ class Storycraft(Module):
|
||||
player.userhost = result['userhost']
|
||||
|
||||
return player
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during get player by userhost")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_completed_games(self):
|
||||
"""Get the games with COMPLETED status."""
|
||||
@ -819,20 +833,20 @@ class Storycraft(Module):
|
||||
"""Return the in progress/open games that include the player nick."""
|
||||
|
||||
games = []
|
||||
db = self.get_db()
|
||||
try:
|
||||
# get the games of specified type and populate a list
|
||||
db = self.get_db()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = '''
|
||||
SELECT game.id, game.round_mode, game.game_length, game.line_length,
|
||||
game.random_method, game.lines_per_turn, game.status, game.owner_nick,
|
||||
game.owner_userhost, game.start_time, game.end_time
|
||||
FROM storycraft_game game
|
||||
INNER JOIN storycraft_player player ON player.game_id = game.id
|
||||
WHERE player.nick = ? AND (game.status = 'OPEN' OR game.status = 'IN PROGRESS')
|
||||
WHERE player.nick = %s AND (game.status = 'OPEN' OR game.status = 'IN PROGRESS')
|
||||
'''
|
||||
cursor = db.execute(query, (player_nick,))
|
||||
results = cursor.fetchall()
|
||||
db.close()
|
||||
cur.execute(query, (player_nick,))
|
||||
results = cur.fetchall()
|
||||
for result in results:
|
||||
game = self.StorycraftGame()
|
||||
|
||||
@ -851,10 +865,11 @@ class Storycraft(Module):
|
||||
games.append(game)
|
||||
|
||||
return games
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during get active games with player")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_games_waiting_on_player(self, player_nick):
|
||||
"""Return the games where the player nick is the owner of a pending line.
|
||||
@ -864,9 +879,10 @@ class Storycraft(Module):
|
||||
"""
|
||||
|
||||
games = []
|
||||
db = self.get_db()
|
||||
try:
|
||||
# get the games of specified type and populate a list
|
||||
db = self.get_db()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = '''
|
||||
SELECT game.id, game.round_mode, game.game_length, game.line_length,
|
||||
game.random_method, game.lines_per_turn, game.status, game.owner_nick,
|
||||
@ -874,56 +890,16 @@ class Storycraft(Module):
|
||||
FROM storycraft_game game
|
||||
INNER JOIN storycraft_player player ON player.game_id = game.id
|
||||
INNER JOIN storycraft_line line ON line.player_id = player.id
|
||||
WHERE player.nick = ? AND game.status = 'IN PROGRESS' AND line.line = ''
|
||||
WHERE player.nick = %s AND game.status = 'IN PROGRESS' AND line.line = ''
|
||||
UNION
|
||||
SELECT game.id, game.round_mode, game.game_length, game.line_length,
|
||||
game.random_method, game.lines_per_turn, game.status, game.owner_nick,
|
||||
game.owner_userhost, game.start_time, game.end_time
|
||||
FROM storycraft_game game
|
||||
WHERE game.owner_nick = ? AND game.status = 'OPEN'
|
||||
WHERE game.owner_nick = %s AND game.status = 'OPEN'
|
||||
'''
|
||||
cursor = db.execute(query, (player_nick, player_nick))
|
||||
results = cursor.fetchall()
|
||||
db.close()
|
||||
for result in results:
|
||||
game = self.StorycraftGame()
|
||||
|
||||
game.id = int(result['game.id'])
|
||||
game.round_mode = int(result['game.round_mode'])
|
||||
game.game_length = int(result['game.game_length'])
|
||||
game.line_length = int(result['game.line_length'])
|
||||
game.random_method = int(result['game.random_method'])
|
||||
game.lines_per_turn = int(result['game.lines_per_turn'])
|
||||
game.status = result['game.status']
|
||||
game.owner_nick = result['game.owner_nick']
|
||||
game.owner_userhost = result['game.owner_userhost']
|
||||
game.start_time = result['game.start_time']
|
||||
game.end_time = result['game.end_time']
|
||||
|
||||
games.append(game)
|
||||
|
||||
return games
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
raise
|
||||
|
||||
def _get_games_of_type(self, game_type):
|
||||
"""Return the games of the specified type."""
|
||||
|
||||
games = []
|
||||
try:
|
||||
# get the games of specified type and populate a list
|
||||
db = self.get_db()
|
||||
query = '''
|
||||
SELECT id, round_mode, game_length, line_length, random_method,
|
||||
lines_per_turn, status, owner_nick, owner_userhost, start_time,
|
||||
end_time
|
||||
FROM storycraft_game WHERE status = ?
|
||||
'''
|
||||
cursor = db.execute(query, (game_type,))
|
||||
results = cursor.fetchall()
|
||||
db.close()
|
||||
cur.execute(query, (player_nick, player_nick))
|
||||
results = cur.fetchall()
|
||||
for result in results:
|
||||
game = self.StorycraftGame()
|
||||
|
||||
@ -942,29 +918,71 @@ class Storycraft(Module):
|
||||
games.append(game)
|
||||
|
||||
return games
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during get games waiting on player")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_games_of_type(self, game_type):
|
||||
"""Return the games of the specified type."""
|
||||
|
||||
games = []
|
||||
db = self.get_db()
|
||||
try:
|
||||
# get the games of specified type and populate a list
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = '''
|
||||
SELECT id, round_mode, game_length, line_length, random_method,
|
||||
lines_per_turn, status, owner_nick, owner_userhost, start_time,
|
||||
end_time
|
||||
FROM storycraft_game WHERE status = %s
|
||||
'''
|
||||
cur.execute(query, (game_type,))
|
||||
results = cur.fetchall()
|
||||
for result in results:
|
||||
game = self.StorycraftGame()
|
||||
|
||||
game.id = int(result['id'])
|
||||
game.round_mode = int(result['round_mode'])
|
||||
game.game_length = int(result['game_length'])
|
||||
game.line_length = int(result['line_length'])
|
||||
game.random_method = int(result['random_method'])
|
||||
game.lines_per_turn = int(result['lines_per_turn'])
|
||||
game.status = result['status']
|
||||
game.owner_nick = result['owner_nick']
|
||||
game.owner_userhost = result['owner_userhost']
|
||||
game.start_time = result['start_time']
|
||||
game.end_time = result['end_time']
|
||||
|
||||
games.append(game)
|
||||
|
||||
return games
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during get games of type")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _add_player_to_game(self, game_id, nick, userhost):
|
||||
"""Add a player to a game, so that they may eventually play."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = '''
|
||||
INSERT INTO storycraft_player (game_id, nick, userhost)
|
||||
VALUES (?, ?, ?)
|
||||
VALUES (%s, %s, %s)
|
||||
'''
|
||||
cur.execute(statement, (game_id, nick, userhost))
|
||||
db.commit()
|
||||
db.close()
|
||||
return cur.lastrowid
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
self.log.error("database error during add player to game")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_player_exists_in_game(self, game_id, userhost):
|
||||
"""Return the existence of a player in a game."""
|
||||
@ -998,19 +1016,20 @@ class Storycraft(Module):
|
||||
"""Return the number of games of the specified type."""
|
||||
|
||||
count = 0
|
||||
db = self.get_db()
|
||||
try:
|
||||
# get count of game_type games
|
||||
db = self.get_db()
|
||||
query = 'SELECT COUNT(*) FROM storycraft_game WHERE status = ?'
|
||||
cursor = db.execute(query, (game_type,))
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = 'SELECT COUNT(*) FROM storycraft_game WHERE status = %s'
|
||||
cur.execute(query, (game_type,))
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
count = result['COUNT(*)']
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during get game type count")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
return count
|
||||
|
||||
@ -1018,19 +1037,20 @@ class Storycraft(Module):
|
||||
"""Return the current game server concurrency."""
|
||||
|
||||
concurrency = 0
|
||||
db = self.get_db()
|
||||
try:
|
||||
# get the concurrency value from config table
|
||||
db = self.get_db()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = 'SELECT concurrent_games FROM storycraft_config'
|
||||
cursor = db.execute(query)
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur.execute(query)
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
concurrency = result['concurrent_games']
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during get concurrent game count")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
return concurrency
|
||||
|
||||
@ -1038,17 +1058,17 @@ class Storycraft(Module):
|
||||
"""Get the lines for the specified game_id."""
|
||||
|
||||
lines = []
|
||||
db = self.get_db()
|
||||
try:
|
||||
# get the games of specified type and populate a list
|
||||
db = self.get_db()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = '''
|
||||
SELECT id, game_id, player_id, line, time
|
||||
FROM storycraft_line WHERE game_id = ?
|
||||
FROM storycraft_line WHERE game_id = %s
|
||||
ORDER BY time DESC, id DESC
|
||||
'''
|
||||
cursor = db.execute(query, (game_id,))
|
||||
results = cursor.fetchall()
|
||||
db.close()
|
||||
cur.execute(query, (game_id,))
|
||||
results = cur.fetchall()
|
||||
for result in results:
|
||||
line = self.StorycraftLine()
|
||||
|
||||
@ -1061,28 +1081,30 @@ class Storycraft(Module):
|
||||
lines.append(line)
|
||||
|
||||
return lines
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during get lines for game")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _update_line(self, line_id, input_line):
|
||||
"""Update the specified line with the given text."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = '''
|
||||
UPDATE storycraft_line SET line = ?, time = CURRENT_TIMESTAMP WHERE id = ?
|
||||
UPDATE storycraft_line SET line = %s, time = CURRENT_TIMESTAMP WHERE id = %s
|
||||
'''
|
||||
cur.execute(statement, (input_line.decode('utf-8', 'replace'), line_id))
|
||||
db.commit()
|
||||
db.close()
|
||||
return line_id
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
self.log.error("database error during update line")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _export_game_to_disk(self, game, lines):
|
||||
"""Write a game to disk."""
|
||||
@ -1118,18 +1140,18 @@ class Storycraft(Module):
|
||||
def _get_storycraft_settings(self):
|
||||
"""Get the server settings."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
# get the settings and return in StorycraftSettings
|
||||
db = self.get_db()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = '''
|
||||
SELECT master_channel, concurrent_games, default_round_mode,
|
||||
default_game_length, default_line_length, default_random_method,
|
||||
default_lines_per_turn
|
||||
FROM storycraft_config
|
||||
'''
|
||||
cursor = db.execute(query)
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur.execute(query)
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
settings = self.StorycraftSettings()
|
||||
|
||||
@ -1142,9 +1164,10 @@ class Storycraft(Module):
|
||||
settings.default_lines_per_turn = int(result['default_lines_per_turn'])
|
||||
|
||||
return settings
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error('sqlite error: ' + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error during get storycraft settings")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
# vi:tabstop=4:expandtab:autoindent
|
||||
|
@ -19,11 +19,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
from ConfigParser import NoSectionError, NoOptionError
|
||||
import oauth2 as oauth
|
||||
import re
|
||||
import sqlite3
|
||||
import thread
|
||||
import time
|
||||
import urlparse
|
||||
|
||||
import MySQLdb as mdb
|
||||
|
||||
from extlib import irclib
|
||||
from extlib import twitter
|
||||
|
||||
@ -96,41 +97,28 @@ class Twitter(Module):
|
||||
# init the table if it doesn't exist
|
||||
version = self.db_module_registered(self.__class__.__name__)
|
||||
if version == None or version < 1:
|
||||
# create tables
|
||||
db = self.get_db()
|
||||
# create tables
|
||||
try:
|
||||
version = 1
|
||||
|
||||
db.execute("""
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
cur.execute("""
|
||||
CREATE TABLE twitter_settings (
|
||||
since_id INTEGER NOT NULL,
|
||||
output_channel TEXT NOT NULL
|
||||
)""")
|
||||
db.execute("""INSERT INTO twitter_settings (since_id, output_channel) VALUES (0, '#drbotzo')""")
|
||||
since_id SERIAL,
|
||||
output_channel VARCHAR(64) NOT NULL,
|
||||
oauth_token VARCHAR(256) DEFAULT NULL,
|
||||
oauth_token_secret VARCHAR(256) DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
""")
|
||||
cur.execute("""INSERT INTO twitter_settings (since_id, output_channel) VALUES (0, '#drbotzo')""")
|
||||
db.commit()
|
||||
db.close()
|
||||
self.db_register_module_version(self.__class__.__name__, version)
|
||||
except sqlite3.Error as e:
|
||||
except mdb.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
raise
|
||||
if version < 2:
|
||||
db = self.get_db()
|
||||
try:
|
||||
version = 2
|
||||
|
||||
db.execute("""ALTER TABLE twitter_settings ADD COLUMN oauth_token TEXT DEFAULT NULL""")
|
||||
db.execute("""ALTER TABLE twitter_settings ADD COLUMN oauth_token_secret TEXT DEFAULT NULL""")
|
||||
|
||||
db.commit()
|
||||
db.close()
|
||||
self.db_register_module_version(self.__class__.__name__, version)
|
||||
except sqlite3.Error as e:
|
||||
db.rollback()
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
self.log.error("database error trying to create tables")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def shutdown(self):
|
||||
"""Deauth, and make the twitter API item inoperable."""
|
||||
@ -395,49 +383,51 @@ class Twitter(Module):
|
||||
def _get_last_since_id(self):
|
||||
"""Get the since_id out of the database."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = "SELECT since_id FROM twitter_settings"
|
||||
cursor = db.execute(query)
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur.execute(query)
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
return result['since_id']
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error getting last since ID")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_output_channel(self):
|
||||
"""Get the output_channel out of the database."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = "SELECT output_channel FROM twitter_settings"
|
||||
cursor = db.execute(query)
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur.execute(query)
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
return result['output_channel']
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error getting output channel")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _set_last_since_id(self, since_id):
|
||||
"""Set the since_id."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
statement = "UPDATE twitter_settings SET since_id = ?"
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = "UPDATE twitter_settings SET since_id = %s"
|
||||
cur.execute(statement, (since_id,))
|
||||
db.commit()
|
||||
db.close()
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error saving last since ID")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _get_latest_tweet_id(self, tweets, since_id):
|
||||
"""Find the latest tweet id in the provided list, or the given since_id."""
|
||||
@ -452,34 +442,34 @@ class Twitter(Module):
|
||||
def _persist_auth_tokens(self, oauth_token, oauth_token_secret):
|
||||
"""Save the auth tokens to the database, with the intent of reusing them."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor()
|
||||
statement = "UPDATE twitter_settings SET oauth_token = ?, oauth_token_secret = ?"
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
statement = "UPDATE twitter_settings SET oauth_token = %s, oauth_token_secret = %s"
|
||||
cur.execute(statement, (oauth_token, oauth_token_secret))
|
||||
db.commit()
|
||||
db.close()
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error saving auth tokens")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
finally: cur.close()
|
||||
|
||||
def _retrieve_stored_auth_tokens(self):
|
||||
"""Check the database for existing auth tokens, try reusing them."""
|
||||
|
||||
db = self.get_db()
|
||||
try:
|
||||
db = self.get_db()
|
||||
cur = db.cursor(mdb.cursors.DictCursor)
|
||||
query = "SELECT oauth_token, oauth_token_secret FROM twitter_settings"
|
||||
cursor = db.execute(query)
|
||||
result = cursor.fetchone()
|
||||
db.close()
|
||||
cur.execute(query)
|
||||
result = cur.fetchone()
|
||||
if result:
|
||||
return (result['oauth_token'], result['oauth_token_secret'])
|
||||
except sqlite3.Error as e:
|
||||
db.close()
|
||||
self.log.error("sqlite error: " + str(e))
|
||||
except mdb.Error as e:
|
||||
self.log.error("database error retrieving auth tokens")
|
||||
self.log.exception(e)
|
||||
raise
|
||||
|
||||
finally: cur.close()
|
||||
|
||||
# vi:tabstop=4:expandtab:autoindent
|
||||
# kate: indent-mode python;indent-width 4;replace-tabs on;
|
||||
|
@ -1,3 +1,4 @@
|
||||
MySQL-python==1.2.3
|
||||
httplib2==0.7.4
|
||||
oauth2==1.5.211
|
||||
ply==3.4
|
||||
|
Loading…
Reference in New Issue
Block a user