mirror of https://github.com/Mikaela/Limnoria.git
* LOTS of updates to the MoobotFactoids test suite, parts of which aren't ready
yet, but the test targets should be pretty static from here on out, except adding new tests. * Fixed up lock and coded unlock in MoobotFactoids (actually, factored the common code out into one helper function that each call). * Added the changeFactoids (=~) portion. * Changed the table structure again (should be the last time). Locked_by was redundant if we're only going to let factoid creators lock/unlock. Removed it.
This commit is contained in:
parent
f567f36e4c
commit
ddfd7e10e1
|
@ -125,7 +125,7 @@ def pick(L, recursed=False):
|
||||||
|
|
||||||
class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
|
class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
|
||||||
priority = 1000
|
priority = 1000
|
||||||
addressedRegexps = sets.Set(['addFactoids'])
|
addressedRegexps = sets.Set(['addFactoids', 'changeFactoids'])
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
||||||
self.makeDB(dbfilename)
|
self.makeDB(dbfilename)
|
||||||
|
@ -149,7 +149,6 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
|
||||||
created_at TIMESTAMP,
|
created_at TIMESTAMP,
|
||||||
modified_by INTEGER,
|
modified_by INTEGER,
|
||||||
modified_at TIMESTAMP,
|
modified_at TIMESTAMP,
|
||||||
locked_by INTEGER,
|
|
||||||
locked_at TIMESTAMP,
|
locked_at TIMESTAMP,
|
||||||
last_requested_by TEXT,
|
last_requested_by TEXT,
|
||||||
last_requested_at TIMESTAMP,
|
last_requested_at TIMESTAMP,
|
||||||
|
@ -237,12 +236,47 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
|
||||||
return
|
return
|
||||||
# Otherwise,
|
# Otherwise,
|
||||||
cursor.execute("""INSERT INTO factoids VALUES
|
cursor.execute("""INSERT INTO factoids VALUES
|
||||||
(%s, %s, %s, NULL, NULL, NULL, NULL, NULL, NULL,
|
(%s, %s, %s, NULL, NULL, NULL, NULL, NULL,
|
||||||
%s, 0)""",
|
%s, 0)""",
|
||||||
key, id, int(time.time()), fact)
|
key, id, int(time.time()), fact)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
irc.reply(msg, conf.replySuccess)
|
irc.reply(msg, conf.replySuccess)
|
||||||
|
|
||||||
|
def changeFactoids(self, irc, msg, match):
|
||||||
|
r"(\S+)\s+=~\s+(\S+)"
|
||||||
|
# Must be registered!
|
||||||
|
try:
|
||||||
|
id = ircdb.users.getUserId(msg.prefix)
|
||||||
|
except KeyError:
|
||||||
|
irc.error(msg, conf.replyNotRegistered)
|
||||||
|
return
|
||||||
|
key, regexp = match.groups()
|
||||||
|
cursor = self.db.cursor()
|
||||||
|
# Check and make sure it's in the DB
|
||||||
|
cursor.execute("""SELECT locked_at, fact FROM factoids
|
||||||
|
WHERE key = %s""", key)
|
||||||
|
if cursor.rowcount == 0:
|
||||||
|
irc.error(msg, "Factoid '%s' not found." % key)
|
||||||
|
return
|
||||||
|
# No dice if it's locked, no matter who it is
|
||||||
|
(locked_at, fact) = cursor.fetchone()
|
||||||
|
if locked_at is not None:
|
||||||
|
irc.error(msg, "Factoid '%s' is locked." % key)
|
||||||
|
return
|
||||||
|
# It's fair game if we get to here
|
||||||
|
try:
|
||||||
|
r = utils.perlReToReplacer(regexp)
|
||||||
|
except ValueError, e:
|
||||||
|
irc.error(msg, "Invalid regexp: %s" % regexp)
|
||||||
|
return
|
||||||
|
new_fact = r(fact)
|
||||||
|
cursor.execute("""UPDATE factoids
|
||||||
|
SET fact = %s, modified_by = %s,
|
||||||
|
modified_at = %s WHERE key = %s""",
|
||||||
|
new_fact, id, int(time.time()), key)
|
||||||
|
self.db.commit()
|
||||||
|
irc.reply(msg, conf.replySuccess)
|
||||||
|
|
||||||
def literal(self, irc, msg, args):
|
def literal(self, irc, msg, args):
|
||||||
"""<factoid key>
|
"""<factoid key>
|
||||||
|
|
||||||
|
@ -271,14 +305,13 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
|
||||||
cursor = self.db.cursor()
|
cursor = self.db.cursor()
|
||||||
cursor.execute("""SELECT created_by, created_at, modified_by,
|
cursor.execute("""SELECT created_by, created_at, modified_by,
|
||||||
modified_at, last_requested_by, last_requested_at,
|
modified_at, last_requested_by, last_requested_at,
|
||||||
requested_count, locked_by, locked_at FROM
|
requested_count, locked_at FROM
|
||||||
factoids WHERE key = %s""", key)
|
factoids WHERE key = %s""", key)
|
||||||
if cursor.rowcount == 0:
|
if cursor.rowcount == 0:
|
||||||
irc.error(msg, "No such factoid: %s" % key)
|
irc.error(msg, "No such factoid: %s" % key)
|
||||||
return
|
return
|
||||||
(created_by, created_at, modified_by, modified_at, last_requested_by,
|
(created_by, created_at, modified_by, modified_at, last_requested_by,
|
||||||
last_requested_at, requested_count, locked_by, locked_at) = \
|
last_requested_at, requested_count, locked_at) = cursor.fetchone()
|
||||||
cursor.fetchone()
|
|
||||||
# First, creation info.
|
# First, creation info.
|
||||||
# Map the integer created_by to the username
|
# Map the integer created_by to the username
|
||||||
creat_by = ircdb.users.getUser(created_by).name
|
creat_by = ircdb.users.getUser(created_by).name
|
||||||
|
@ -297,45 +330,72 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
|
||||||
last_at = time.strftime(conf.humanTimestampFormat,
|
last_at = time.strftime(conf.humanTimestampFormat,
|
||||||
time.localtime(int(last_requested_at)))
|
time.localtime(int(last_requested_at)))
|
||||||
req_count = requested_count
|
req_count = requested_count
|
||||||
s += " Last requested by %s on %s, requested %s times." % \
|
times_str = utils.nItems(requested_count, 'time')
|
||||||
(last_by, last_at, req_count)
|
s += " Last requested by %s on %s, requested %s." % \
|
||||||
|
(last_by, last_at, times_str)
|
||||||
# Last, locked info
|
# Last, locked info
|
||||||
if locked_by is not None:
|
if locked_at is not None:
|
||||||
lock_by = ircdb.users.getUser(locked_by).name
|
|
||||||
lock_at = time.strftime(conf.humanTimestampFormat,
|
lock_at = time.strftime(conf.humanTimestampFormat,
|
||||||
time.localtime(int(locked_at)))
|
time.localtime(int(locked_at)))
|
||||||
s += " Locked by %s on %s." % (lock_by, lock_at)
|
s += " Locked on %s." % lock_at
|
||||||
irc.reply(msg, s)
|
irc.reply(msg, s)
|
||||||
|
|
||||||
|
|
||||||
|
def _lock(self, irc, msg, args, lock=True):
|
||||||
|
try:
|
||||||
|
id = ircdb.users.getUserId(msg.prefix)
|
||||||
|
except KeyError:
|
||||||
|
irc.error(msg, conf.replyNotRegistered)
|
||||||
|
return
|
||||||
|
key = privmsgs.getArgs(args, needed=1)
|
||||||
|
cursor = self.db.cursor()
|
||||||
|
cursor.execute("""SELECT created_by, locked_at FROM factoids
|
||||||
|
WHERE key = %s""", key)
|
||||||
|
if cursor.rowcount == 0:
|
||||||
|
irc.error(msg, "No such factoid: %s" % key)
|
||||||
|
return
|
||||||
|
(created_by, locked_at) = cursor.fetchone()
|
||||||
|
# Don't perform redundant operations
|
||||||
|
if lock:
|
||||||
|
if locked_at is not None:
|
||||||
|
irc.error(msg, "Factoid '%s' is already locked." % key)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
if locked_at is None:
|
||||||
|
irc.error(msg, "Factoid '%s' is not locked." % key)
|
||||||
|
return
|
||||||
|
# Can only lock/unlock own factoids
|
||||||
|
if created_by != id:
|
||||||
|
s = "unlock"
|
||||||
|
if lock:
|
||||||
|
s = "lock"
|
||||||
|
irc.error(msg, "Cannot %s someone else's factoid." % s)
|
||||||
|
return
|
||||||
|
# Okay, we're done, ready to lock/unlock
|
||||||
|
if lock:
|
||||||
|
locked_at = int(time.time())
|
||||||
|
else:
|
||||||
|
locked_at = None
|
||||||
|
cursor.execute("""UPDATE factoids SET locked_at = %s
|
||||||
|
WHERE key = %s""", locked_at, key)
|
||||||
|
self.db.commit()
|
||||||
|
irc.reply(msg, conf.replySuccess)
|
||||||
|
|
||||||
def lock(self, irc, msg, args):
|
def lock(self, irc, msg, args):
|
||||||
"""<factoid key>
|
"""<factoid key>
|
||||||
|
|
||||||
Locks the factoid with the given factoid key. Requires that the user
|
Locks the factoid with the given factoid key. Requires that the user
|
||||||
be registered and have created the factoid originally.
|
be registered and have created the factoid originally.
|
||||||
"""
|
"""
|
||||||
try:
|
self._lock(irc, msg, args, True)
|
||||||
id = ircdb.users.getUserId(msg.prefix)
|
|
||||||
except KeyError:
|
def unlock(self, irc, msg, args):
|
||||||
irc.error(msg, conf.replyNotRegistered)
|
"""<factoid key>
|
||||||
return
|
|
||||||
key = privmsgs.getArgs(args, needed=1)
|
Unlocks the factoid with the given factoid key. Requires that the
|
||||||
cursor = self.db.cursor()
|
user be registered and have locked the factoid.
|
||||||
cursor.execute("""SELECT created_by, locked_by FROM factoids
|
"""
|
||||||
WHERE key = %s""", key)
|
self._lock(irc, msg, args, False)
|
||||||
if cursor.rowcount == 0:
|
|
||||||
irc.error(msg, "No such factoid: %s" % key)
|
|
||||||
return
|
|
||||||
(created_by, locked_by) = cursor.fetchone()
|
|
||||||
if locked_by is not None:
|
|
||||||
irc.error(msg, "Factoid '%s' is already locked." % key)
|
|
||||||
return
|
|
||||||
if created_by != id:
|
|
||||||
irc.error(msg, "Cannot lock someone else's factoid." % key)
|
|
||||||
return
|
|
||||||
cursor.execute("""UPDATE factoids SET locked_by = %s, locked_at = %s
|
|
||||||
WHERE key = %s""", id, int(time.time()), key)
|
|
||||||
self.db.commit()
|
|
||||||
irc.reply(msg, conf.replySuccess)
|
|
||||||
|
|
||||||
Class = MoobotFactoids
|
Class = MoobotFactoids
|
||||||
|
|
||||||
|
|
|
@ -44,24 +44,110 @@ if sqlite is not None:
|
||||||
# Create a valid user to use
|
# Create a valid user to use
|
||||||
self.prefix = 'foo!bar@baz'
|
self.prefix = 'foo!bar@baz'
|
||||||
self.assertNotError('register tester moo')
|
self.assertNotError('register tester moo')
|
||||||
|
|
||||||
def testLiteral(self):
|
def testLiteral(self):
|
||||||
self.assertError('literal moo') # no factoids yet
|
self.assertError('literal moo') # no factoids yet
|
||||||
self.assertNotError('moo is <reply>foo')
|
self.assertNotError('moo is <reply>foo')
|
||||||
self.assertRegexp('literal moo', '<reply>foo')
|
self.assertResponse('literal moo', '<reply>foo')
|
||||||
self.assertNotError('moo2 is moo!')
|
self.assertNotError('moo2 is moo!')
|
||||||
self.assertRegexp('literal moo2', 'moo!')
|
self.assertResponse('literal moo2', 'moo!')
|
||||||
self.assertNotError('moo3 is <action>foo')
|
self.assertNotError('moo3 is <action>foo')
|
||||||
self.assertRegexp('literal moo3', '<action>foo')
|
self.assertResponse('literal moo3', '<action>foo')
|
||||||
|
|
||||||
def testGetFactoid(self):
|
def testGetFactoid(self):
|
||||||
self.assertNotError('moo is <reply>foo')
|
self.assertNotError('moo is <reply>foo')
|
||||||
self.assertRegexp('moo', 'foo')
|
self.assertResponse('moo', 'foo')
|
||||||
self.assertNotError('moo2 is moo!')
|
self.assertNotError('moo2 is moo!')
|
||||||
self.assertRegexp('moo2', 'moo2 is moo!')
|
self.assertResponse('moo2', 'moo2 is moo!')
|
||||||
self.assertNotError('moo3 is <action>foo')
|
self.assertNotError('moo3 is <action>foo')
|
||||||
self.assertAction('moo3', 'foo')
|
self.assertAction('moo3', 'foo')
|
||||||
|
# Test and make sure it's parsing
|
||||||
|
self.assertNotError('moo4 is <reply>(1|2|3)')
|
||||||
|
self.assertRegexp('moo4', '^(1|2|3)$')
|
||||||
|
|
||||||
|
def testFactinfo(self):
|
||||||
|
self.assertNotError('moo is <reply>foo')
|
||||||
|
self.assertRegexp('factinfo moo', '^moo: Created by tester on.*$')
|
||||||
|
self.assertNotError('moo')
|
||||||
|
self.assertRegexp('factinfo moo', '^moo: Created by tester on'
|
||||||
|
'.*?\. Last requested by foo!bar@baz on .*?, '
|
||||||
|
'requested 1 time.$')
|
||||||
|
self.assertNotError('moo')
|
||||||
|
self.assertRegexp('factinfo moo', '^moo: Created by tester on'
|
||||||
|
'.*?\. Last requested by foo!bar@baz on .*?, '
|
||||||
|
'requested 2 times.$')
|
||||||
|
self.assertNotError('moo =~ s/foo/bar/')
|
||||||
|
self.assertRegexp('factinfo moo', '^moo: Created by tester on'
|
||||||
|
'.*?\. Last modified by tester on .*?\. '
|
||||||
|
'Last requested by foo!bar@baz on .*?, '
|
||||||
|
'requested 2 times.$')
|
||||||
|
self.assertNotError('lock moo')
|
||||||
|
self.assertRegexp('factinfo moo', '^moo: Created by tester on'
|
||||||
|
'.*?\. Last modified by tester on .*?\. '
|
||||||
|
'Last requested by foo!bar@baz on .*?, '
|
||||||
|
'requested 2 times. Locked on .*\.$')
|
||||||
|
self.assertNotError('unlock moo')
|
||||||
|
self.assertRegexp('factinfo moo', '^moo: Created by tester on'
|
||||||
|
'.*?\. Last modified by tester on .*?\. '
|
||||||
|
'Last requested by foo!bar@baz on .*?, '
|
||||||
|
'requested 2 times.$')
|
||||||
|
|
||||||
|
def testLockUnlock(self):
|
||||||
|
self.assertNotError('moo is <reply>moo')
|
||||||
|
self.assertNotError('lock moo')
|
||||||
|
self.assertRegexp('factinfo moo', '^moo: Created by tester on'
|
||||||
|
'.*?\. Locked on .*?\.')
|
||||||
|
# switch user
|
||||||
|
self.prefix = 'moo!moo@moo'
|
||||||
|
self.assertNotError('register nottester moo')
|
||||||
|
self.assertError('unlock moo')
|
||||||
|
self.assertRegexp('factinfo moo', '^moo: Created by tester on'
|
||||||
|
'.*?\. Locked on .*?\.')
|
||||||
|
# switch back
|
||||||
|
self.prefix = 'foo!bar@baz'
|
||||||
|
self.assertNotError('identify tester moo')
|
||||||
|
self.assertNotError('unlock moo')
|
||||||
|
self.assertRegexp('factinfo moo', '^moo: Created by tester on'
|
||||||
|
'.*?\.')
|
||||||
|
|
||||||
|
def testChangeFactoid(self):
|
||||||
|
self.assertNotError('moo is <reply>moo')
|
||||||
|
self.assertNotError('moo =~ s/moo/moos/')
|
||||||
|
self.assertResponse('moo', 'moos')
|
||||||
|
self.assertNotError('moo =~ s/reply/action/')
|
||||||
|
self.assertAction('moo', 'moos')
|
||||||
|
self.assertNotError('moo =~ s/moos/(moos|woofs)/')
|
||||||
|
self.assertActionRegexp('moo', '^(moos|woofs)$')
|
||||||
|
self.assertError('moo =~ s/moo/')
|
||||||
|
|
||||||
|
def testListkeys(self):
|
||||||
|
self.assertResponse('listkeys *', 'No keys found matching \'*\'.')
|
||||||
|
self.assertNotError('moo is <reply>moo')
|
||||||
|
self.assertResponse('listkeys moo', 'Key search for \'moo\' '
|
||||||
|
'(1 found): moo')
|
||||||
|
self.assertResponse('listkeys foo', 'No keys found matching '
|
||||||
|
'\'foo\'.')
|
||||||
|
# Throw in a bunch more
|
||||||
|
for i in range(10):
|
||||||
|
self.assertNotError('moo%s is <reply>moo' % i)
|
||||||
|
self.assertRegexp('listkeys moo', '^Key search for \'moo\' '
|
||||||
|
'(11 found): (moo\d*, )+ and moo9$')
|
||||||
|
self.assertRegexp('listkeys *', '^Key search for \'*\' '
|
||||||
|
'(12 found): foo, (moo\d*, )+ and moo9$')
|
||||||
|
|
||||||
|
def testListvalues(self):
|
||||||
|
self.assertNotError('moo is <reply>moo')
|
||||||
|
self.assertResponse('listvalues moo', 'Value search for \'moo\' '
|
||||||
|
'(1 found): moo')
|
||||||
|
|
||||||
|
def testListauth(self):
|
||||||
|
self.assertNotError('moo is <reply>moo')
|
||||||
|
self.assertResponse('listauth tester', 'Author search for tester '
|
||||||
|
'(1 found): moo')
|
||||||
|
|
||||||
|
class DunnoTestCase(PluginTestCase, PluginDocumentation):
|
||||||
|
plugins = ('MiscCommands', 'MoobotFactoids', 'UserCommands')
|
||||||
|
def testDunno(self):
|
||||||
|
self.assertNotError('apfasdfjoia') # Should say a dunno, no error
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue