From a5ba65cf6f1bdfce2ae9fa57f038b34310b4d9e8 Mon Sep 17 00:00:00 2001 From: Daniel DiPaolo Date: Sat, 29 Jan 2005 20:07:22 +0000 Subject: [PATCH] Initial conversion of QuoteGrabs and addition of QG.search --- plugins/QuoteGrabs/README.txt | 1 + plugins/QuoteGrabs/__init__.py | 56 ++++++ plugins/QuoteGrabs/config.py | 65 +++++++ plugins/QuoteGrabs/plugin.py | 346 +++++++++++++++++++++++++++++++++ plugins/QuoteGrabs/test.py | 109 +++++++++++ 5 files changed, 577 insertions(+) create mode 100644 plugins/QuoteGrabs/README.txt create mode 100644 plugins/QuoteGrabs/__init__.py create mode 100644 plugins/QuoteGrabs/config.py create mode 100644 plugins/QuoteGrabs/plugin.py create mode 100644 plugins/QuoteGrabs/test.py diff --git a/plugins/QuoteGrabs/README.txt b/plugins/QuoteGrabs/README.txt new file mode 100644 index 000000000..d60b47a97 --- /dev/null +++ b/plugins/QuoteGrabs/README.txt @@ -0,0 +1 @@ +Insert a description of your plugin here, with any notes, etc. about using it. diff --git a/plugins/QuoteGrabs/__init__.py b/plugins/QuoteGrabs/__init__.py new file mode 100644 index 000000000..5fd518bf0 --- /dev/null +++ b/plugins/QuoteGrabs/__init__.py @@ -0,0 +1,56 @@ +### +# Copyright (c) 2004, Daniel DiPaolo +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +""" +Add a description of the plugin (to be presented to the user inside the wizard) +here. +""" + +import supybot +import supybot.world as world + +# XXX Replace this with an appropriate author or supybot.Author instance. +__author__ = supybot.authors.strike + +# This is a dictionary mapping supybot.Author instances to lists of +# contributions. +__contributors__ = {} + +import config +import plugin +reload(plugin) # In case we're being reloaded. + +if world.testing: + import test + +Class = plugin.Class +configure = config.configure + + +# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: diff --git a/plugins/QuoteGrabs/config.py b/plugins/QuoteGrabs/config.py new file mode 100644 index 000000000..c18a59c10 --- /dev/null +++ b/plugins/QuoteGrabs/config.py @@ -0,0 +1,65 @@ +### +# Copyright (c) 2004, Daniel DiPaolo +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +import supybot.conf as conf +import supybot.registry as registry + +def configure(advanced): + # This will be called by supybot to configure this module. advanced is + # a bool that specifies whether the user identified himself as an advanced + # user or not. You should effect your configuration by manipulating the + # registry as appropriate. + from supybot.questions import expect, anything, something, yn + conf.registerPlugin('QuoteGrabs', True) + + +QuoteGrabs = conf.registerPlugin('QuoteGrabs') +# This is where your configuration variables (if any) should go. For example: +# conf.registerGlobalValue(QuoteGrabs, 'someConfigVariableName', +# registry.Boolean(False, """Help for someConfigVariableName.""")) +conf.registerChannelValue(conf.supybot.plugins.QuoteGrabs, 'randomGrabber', + registry.Boolean(False, """Determines whether the bot will randomly grab + possibly-suitable quotes on occasion. The suitability of a given message + is determined by ...""")) +conf.registerChannelValue(conf.supybot.plugins.QuoteGrabs.randomGrabber, + 'averageTimeBetweenGrabs', + registry.PositiveInteger(864000, """Determines about how many seconds, on + average, should elapse between random grabs. This is only an average + value; grabs can happen from any time after half this time until never, + although that's unlikely to occur.""")) +conf.registerChannelValue(conf.supybot.plugins.QuoteGrabs.randomGrabber, + 'minimumWords', registry.PositiveInteger(3, """Determines the minimum + number of words in a message for it to be considered for random + grabbing.""")) +conf.registerChannelValue(conf.supybot.plugins.QuoteGrabs.randomGrabber, + 'minimumCharacters', registry.PositiveInteger(8, """Determines the + minimum number of characters in a message for it to be considered for + random grabbing.""")) + +# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78 diff --git a/plugins/QuoteGrabs/plugin.py b/plugins/QuoteGrabs/plugin.py new file mode 100644 index 000000000..a3f541998 --- /dev/null +++ b/plugins/QuoteGrabs/plugin.py @@ -0,0 +1,346 @@ +### +# Copyright (c) 2004, Daniel DiPaolo +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +""" +Quotegrabs are like IRC sound bites. When someone says something funny, +incriminating, stupid, outrageous, ... anything that might be worth +remembering, you can grab that quote for that person. With this plugin, you +can store many quotes per person and display their most recent quote, as well +as see who "grabbed" the quote in the first place. +""" + +import os +import time +import random + +import supybot.dbi as dbi +import supybot.conf as conf +import supybot.utils as utils +from supybot.commands import * +import supybot.ircmsgs as ircmsgs +import supybot.plugins as plugins +import supybot.ircutils as ircutils +import supybot.privmsgs as privmsgs +import supybot.callbacks as callbacks + +class QuoteGrabsRecord(dbi.Record): + __fields__ = [ + 'by', + 'text', + 'grabber', + 'at', + 'hostmask', + ] + + def __str__(self): + at = time.strftime(conf.supybot.reply.format.time(), + time.localtime(float(self.at))) + grabber = plugins.getUserName(self.grabber) + return '%s (Said by: %s; grabbed by %s at %s)' % \ + (self.text, self.hostmask, grabber, at) + +class SqliteQuoteGrabsDB(object): + def __init__(self, filename): + self.dbs = ircutils.IrcDict() + self.filename = filename + + def close(self): + for db in self.dbs.itervalues(): + db.close() + + def _getDb(self, channel): + try: + import sqlite + except ImportError: + raise callbacks.Error, 'You need to have PySQLite installed to ' \ + 'use this plugin. Download it at ' \ + '' + filename = plugins.makeChannelFilename(self.filename, channel) + def p(s1, s2): + return int(ircutils.nickEqual(s1, s2)) + if filename in self.dbs: + return self.dbs[filename] + if os.path.exists(filename): + self.dbs[filename] = sqlite.connect(filename, + converters={'bool': bool}) + self.dbs[filename].create_function('nickeq', 2, p) + return self.dbs[filename] + db = sqlite.connect(filename, converters={'bool': bool}) + self.dbs[filename] = db + self.dbs[filename].create_function('nickeq', 2, p) + cursor = db.cursor() + cursor.execute("""CREATE TABLE quotegrabs ( + id INTEGER PRIMARY KEY, + nick TEXT, + hostmask TEXT, + added_by TEXT, + added_at TIMESTAMP, + quote TEXT + );""") + db.commit() + return db + + def get(self, channel, id): + db = self._getDb(channel) + cursor = db.cursor() + cursor.execute("""SELECT id, nick, quote, hostmask, added_at, added_by + FROM quotegrabs WHERE id = %s""", id) + if cursor.rowcount == 0: + raise dbi.NoRecordError + (id, by, quote, hostmask, at, grabber) = cursor.fetchone() + return QuoteGrabsRecord(id, by=by, text=quote, hostmask=hostmask, + at=at, grabber=grabber) + + def random(self, channel, nick): + db = self._getDb(channel) + cursor = db.cursor() + if nick: + cursor.execute("""SELECT quote FROM quotegrabs + WHERE nickeq(nick, %s) + ORDER BY random() LIMIT 1""", + nick) + else: + cursor.execute("""SELECT quote FROM quotegrabs + ORDER BY random() LIMIT 1""") + if cursor.rowcount == 0: + raise dbi.NoRecordError + return cursor.fetchone()[0] + + def list(self, channel, nick): + db = self._getDb(channel) + cursor = db.cursor() + cursor.execute("""SELECT id, quote FROM quotegrabs + WHERE nickeq(nick, %s) + ORDER BY id ASC""", nick) + return [QuoteGrabsRecord(id, text=quote) + for (id, quote) in cursor.fetchall()] + + def getQuote(self, channel, nick): + db = self._getDb(channel) + cursor = db.cursor() + cursor.execute("""SELECT quote FROM quotegrabs + WHERE nickeq(nick, %s) + ORDER BY id DESC LIMIT 1""", nick) + if cursor.rowcount == 0: + raise dbi.NoRecordError + return cursor.fetchone()[0] + + def select(self, channel, nick): + db = self._getDb(channel) + cursor = db.cursor() + cursor.execute("""SELECT added_at FROM quotegrabs + WHERE nickeq(nick, %s) + ORDER BY id DESC LIMIT 1""", nick) + if cursor.rowcount == 0: + raise dbi.NoRecordError + return cursor.fetchone()[0] + + def add(self, msg, by): + channel = msg.args[0] + db = self._getDb(channel) + cursor = db.cursor() + text = ircmsgs.prettyPrint(msg) + # Check to see if the latest quotegrab is identical + cursor.execute("""SELECT quote FROM quotegrabs + WHERE nick=%s + ORDER BY id DESC LIMIT 1""", msg.nick) + if cursor.rowcount != 0: + if text == cursor.fetchone()[0]: + return + cursor.execute("""INSERT INTO quotegrabs + VALUES (NULL, %s, %s, %s, %s, %s)""", + msg.nick, msg.prefix, by, int(time.time()), text) + db.commit() + + def search(self, channel, text): + db = self._getDb(channel) + cursor = db.cursor() + cursor.execute("""SELECT id, quote FROM quotegrabs + WHERE quote LIKE %s + ORDER BY id DESC""", text) + if cursor.rowcount == 0: + raise dbi.NoRecordError + return [QuoteGrabsRecord(id, text=quote) + for (id, quote) in cursor.fetchall()] + +QuoteGrabsDB = plugins.DB('QuoteGrabs', {'sqlite': SqliteQuoteGrabsDB}) + +class QuoteGrabs(callbacks.Privmsg): + """Add the help for "@help QuoteGrabs" here.""" + def __init__(self): + self.__parent = super(QuoteGrabs, self) + self.__parent.__init__() + self.db = QuoteGrabsDB() + + def doPrivmsg(self, irc, msg): + irc = callbacks.SimpleProxy(irc, msg) + if irc.isChannel(msg.args[0]): + (channel, payload) = msg.args + words = self.registryValue('randomGrabber.minimumWords', + channel) + length = self.registryValue('randomGrabber.minimumCharacters', + channel) + grabTime = \ + self.registryValue('randomGrabber.averageTimeBetweenGrabs', + channel) + if self.registryValue('randomGrabber', channel): + if len(payload) > length and len(payload.split()) > words: + try: + last = int(self.db.select(channel, msg.nick)) + except dbi.NoRecordError: + self._grab(irc, msg, irc.prefix) + self._sendGrabMsg(irc, msg) + else: + elapsed = int(time.time()) - last + if random.random()*elapsed > grabTime/2: + self._grab(irc, msg, irc.prefix) + self._sendGrabMsg(irc, msg) + + def _grab(self, irc, msg, addedBy): + self.db.add(msg, addedBy) + + def _sendGrabMsg(self, irc, msg): + s = 'jots down a new quote for %s' % msg.nick + irc.reply(s, action=True, prefixName=False) + + def grab(self, irc, msg, args, channel, nick): + """[] + + Grabs a quote from by for the quotegrabs table. + is only necessary if the message isn't sent in the channel + itself. + """ + # chan is used to make sure we know where to grab the quote from, as + # opposed to channel which is used to determine which db to store the + # quote in + chan = msg.args[0] + if chan is None: + raise callbacks.ArgumentError + if ircutils.nickEqual(nick, msg.nick): + irc.error('You can\'t quote grab yourself.', Raise=True) + for m in reversed(irc.state.history): + if m.command == 'PRIVMSG' and ircutils.nickEqual(m.nick, nick) \ + and ircutils.strEqual(m.args[0], chan): + self._grab(irc, m, msg.prefix) + irc.replySuccess() + return + irc.error('I couldn\'t find a proper message to grab.') + grab = wrap(grab, ['channeldb', 'nick']) + + def quote(self, irc, msg, args, channel, nick): + """[] + + Returns 's latest quote grab in . is only + necessary if the message isn't sent in the channel itself. + """ + try: + irc.reply(self.db.getQuote(channel, nick)) + except dbi.NoRecordError: + irc.error('I couldn\'t find a matching quotegrab for %s.' % nick, + Raise=True) + quote = wrap(quote, ['channeldb', 'nick']) + + def list(self, irc, msg, args, channel, nick): + """[] + + Returns a list of shortened quotes that have been grabbed for + as well as the id of each quote. These ids can be used to get the + full quote. is only necessary if the message isn't sent in + the channel itself. + """ + try: + records = self.db.list(channel, nick) + L = [] + for record in records: + # strip the nick from the quote + quote = record.text.replace('<%s> ' % nick, '', 1) + item = utils.str.ellipsisify('#%s: %s' % (record.id, quote),50) + L.append(item) + irc.reply(utils.str.commaAndify(L)) + except dbi.NoRecordError: + irc.error('I couldn\'t find any quotegrabs for %s.' % nick, + Raise=True) + list = wrap(list, ['channeldb', 'nick']) + + def random(self, irc, msg, args, channel, nick): + """[] [] + + Returns a randomly grabbed quote, optionally choosing only from those + quotes grabbed for . is only necessary if the message + isn't sent in the channel itself. + """ + try: + irc.reply(self.db.random(channel, nick)) + except dbi.NoRecordError: + if nick: + irc.error('Couldn\'t get a random quote for that nick.') + else: + irc.error('Couldn\'t get a random quote. Are there any ' + 'grabbed quotes in the database?') + random = wrap(random, ['channeldb', additional('nick')]) + + def get(self, irc, msg, args, channel, id): + """[] + + Return the quotegrab with the given . is only necessary + if the message isn't sent in the channel itself. + """ + try: + irc.reply(self.db.get(channel, id)) + except dbi.NoRecordError: + irc.error('No quotegrab for id %s' % utils.str.quoted(id), + Raise=True) + get = wrap(get, ['channeldb', 'id']) + + def search(self, irc, msg, args, channel, text): + """[] + + Searches for in a quote. is only necessary if the + message isn't sent in the channel itself. + """ + try: + records = self.db.search(channel, text) + L = [] + for record in records: + # strip the nick from the quote + quote = record.text.replace('<%s> ' % nick, '', 1) + item = utils.str.ellipsisify('#%s: %s' % (record.id, quote),50) + L.append(item) + irc.reply(utils.str.commaAndify(L)) + except dbi.NoRecordError: + irc.error('No quotegrabs matching %s' % utils.str.quoted(text), + Raise=True) + search = wrap(search, ['channeldb', 'text']) + + + +Class = QuoteGrabs + + +# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: diff --git a/plugins/QuoteGrabs/test.py b/plugins/QuoteGrabs/test.py new file mode 100644 index 000000000..f54a9b777 --- /dev/null +++ b/plugins/QuoteGrabs/test.py @@ -0,0 +1,109 @@ +### +# Copyright (c) 2004, Daniel DiPaolo +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from supybot.test import * + +class QuoteGrabsTestCase(PluginTestCase): + plugins = ('QuoteGrabs',) + def testQuoteGrab(self): + testPrefix = 'foo!bar@baz' + self.assertError('grab foo') + # Test join/part/notice (shouldn't grab) + self.irc.feedMsg(ircmsgs.join(self.channel, prefix=testPrefix)) + self.assertError('grab foo') + self.irc.feedMsg(ircmsgs.part(self.channel, prefix=testPrefix)) + self.assertError('grab foo') + # Test privmsgs + self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'something', + prefix=testPrefix)) + self.assertNotError('grab foo') + self.assertResponse('quote foo', ' something') + # Test actions + self.irc.feedMsg(ircmsgs.action(self.channel, 'moos', + prefix=testPrefix)) + self.assertNotError('grab foo') + self.assertResponse('quote foo', '* foo moos') + + def testList(self): + testPrefix = 'foo!bar@baz' + self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'test', + prefix=testPrefix)) + self.assertNotError('grab foo') + self.assertResponse('quotegrabs list foo', '#1: test') + self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'a' * 80, + prefix=testPrefix)) + self.assertNotError('grab foo') + self.assertResponse('quotegrabs list foo', + '#1: test and #2: %s...' %\ + ('a'*43)) # 50 - length of "#2: ..." + + def testDuplicateGrabs(self): + testPrefix = 'foo!bar@baz' + self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'test', + prefix=testPrefix)) + self.assertNotError('grab foo') + self.assertNotError('grab foo') # note:NOTanerror,stillwon'tdupe + self.assertResponse('quotegrabs list foo', '#1: test') + + def testCaseInsensitivity(self): + testPrefix = 'foo!bar@baz' + self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'test', + prefix=testPrefix)) + self.assertNotError('grab FOO') + self.assertNotError('quote foo') + self.assertNotError('quote FoO') + self.assertNotError('quote Foo') + self.assertNotError('quotegrabs list FOO') + self.assertNotError('quotegrabs list fOo') + + def testRandom(self): + testPrefix = 'foo!bar@baz' + self.assertError('random') + self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'test', + prefix=testPrefix)) + self.assertError('random') # still none in the db + self.assertNotError('grab foo') + self.assertResponse('random', ' test') + self.assertResponse('random foo', ' test') + self.assertResponse('random FOO', ' test') + + def testGet(self): + testPrefix= 'foo!bar@baz' + self.assertError('quotegrabs get asdf') + self.assertError('quotegrabs get 1') + self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'test', + prefix=testPrefix)) + self.assertNotError('grab foo') + self.assertNotError('quotegrabs get 1') + +class QuoteGrabsNonChannelTestCase(QuoteGrabsTestCase): + config = { 'databases.plugins.channelSpecific' : False } + + +# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: