mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-23 11:09:23 +01:00
Added Lart and Praise plugins, deprecated FunDB, converted Dunno and Success to the new plugins.ChannelIdDatabasePlugin.
This commit is contained in:
parent
3b5cde224d
commit
3899f33d54
142
plugins/Dunno.py
142
plugins/Dunno.py
@ -28,9 +28,9 @@
|
||||
###
|
||||
|
||||
"""
|
||||
The Dunno module is used to spice up the 'replyWhenNotCommand' behavior with
|
||||
random 'I dunno'-like responses. If you want something spicier than '<x> is
|
||||
not a valid command'-like responses, use this plugin.
|
||||
The Dunno module is used to spice up the reply when given an invalid command
|
||||
with random 'I dunno'-like responses. If you want something spicier than
|
||||
'<x> is not a valid command'-like responses, use this plugin.
|
||||
"""
|
||||
|
||||
import supybot
|
||||
@ -64,46 +64,13 @@ conf.registerChannelValue(conf.supybot.plugins.Dunno, 'prefixNick',
|
||||
registry.Boolean(True, """Determines whether the bot will prefix the nick
|
||||
of the user giving an invalid command to the "dunno" response."""))
|
||||
|
||||
class DbiDunnoDB(plugins.DbiChannelDB):
|
||||
class DB(dbi.DB):
|
||||
class Record(dbi.Record):
|
||||
__fields__ = [
|
||||
'at',
|
||||
'by',
|
||||
'text',
|
||||
]
|
||||
def __init__(self, filename):
|
||||
# We use self.__class__ here because apparently DB isn't in our
|
||||
# scope. python--
|
||||
self.__parent = super(self.__class__, self)
|
||||
self.__parent.__init__(filename)
|
||||
|
||||
def add(self, text, by, at):
|
||||
return self.__parent.add(self.Record(at=at, by=by, text=text))
|
||||
|
||||
def change(self, id, f):
|
||||
dunno = self.get(id)
|
||||
dunno.text = f(dunno.text)
|
||||
self.set(id, dunno)
|
||||
|
||||
DunnoDB = plugins.DB('Dunno', {'flat': DbiDunnoDB})
|
||||
|
||||
class Dunno(callbacks.Privmsg):
|
||||
class Dunno(plugins.ChannelIdDatabasePlugin):
|
||||
"""This plugin was written initially to work with MoobotFactoids, the two
|
||||
of them to provide a similar-to-moobot-and-blootbot interface for factoids.
|
||||
Basically, it replaces the standard 'Error: <X> is not a valid command.'
|
||||
messages with messages kept in a database, able to give more personable
|
||||
responses."""
|
||||
callAfter = ['MoobotFactoids']
|
||||
def __init__(self):
|
||||
self.__parent = super(Dunno, self)
|
||||
self.__parent.__init__()
|
||||
self.db = DunnoDB()
|
||||
|
||||
def die(self):
|
||||
self.db.close()
|
||||
self.__parent.die()
|
||||
|
||||
def invalidCommand(self, irc, msg, tokens):
|
||||
channel = msg.args[0]
|
||||
if ircutils.isChannel(channel):
|
||||
@ -114,107 +81,6 @@ class Dunno(callbacks.Privmsg):
|
||||
dunno = ircutils.standardSubstitute(irc, msg, dunno)
|
||||
irc.reply(dunno, prefixName=prefixName)
|
||||
|
||||
def add(self, irc, msg, args, user, at, channel, dunno):
|
||||
"""[<channel>] <text>
|
||||
|
||||
Adds <text> as a "dunno" to be used as a random response when no
|
||||
command or factoid key matches. Can optionally contain '$who', which
|
||||
will be replaced by the user's name when the dunno is displayed.
|
||||
<channel> is only necessary if the message isn't sent in the channel
|
||||
itself.
|
||||
"""
|
||||
id = self.db.add(channel, dunno, user.id, at)
|
||||
irc.replySuccess('Dunno #%s added.' % id)
|
||||
add = wrap(add, ['user', 'now', 'channeldb', 'text'])
|
||||
|
||||
def remove(self, irc, msg, args, user, channel, id):
|
||||
"""[<channel>] <id>
|
||||
|
||||
Removes dunno with the given <id>. <channel> is only necessary if the
|
||||
message isn't sent in the channel itself.
|
||||
"""
|
||||
# Must be registered to use this
|
||||
try:
|
||||
dunno = self.db.get(channel, id)
|
||||
if user.id != dunno.by:
|
||||
# XXX We need to come up with a way to handle this capability
|
||||
# checking when channel is None. It'll probably involve
|
||||
# something along the lines of using admin instead of
|
||||
# #channel,op. The function should be added to
|
||||
# plugins/__init__.py
|
||||
cap = ircdb.makeChannelCapability(channel, 'op')
|
||||
if not ircdb.users.checkCapability(cap):
|
||||
irc.errorNoCapability(cap)
|
||||
self.db.remove(channel, id)
|
||||
irc.replySuccess()
|
||||
except KeyError:
|
||||
irc.error('No dunno has id #%s.' % id)
|
||||
remove = wrap(remove, ['user', 'channeldb', ('id', 'dunno')])
|
||||
|
||||
def search(self, irc, msg, args, channel, text):
|
||||
"""[<channel>] <text>
|
||||
|
||||
Search for dunno containing the given text. Returns the ids of the
|
||||
dunnos with the text in them. <channel> is only necessary if the
|
||||
message isn't sent in the channel itself.
|
||||
"""
|
||||
def p(dunno):
|
||||
return text.lower() in dunno.text.lower()
|
||||
ids = [str(dunno.id) for dunno in self.db.select(channel, p)]
|
||||
if ids:
|
||||
s = 'Dunno search for %s (%s found): %s.' % \
|
||||
(utils.quoted(text), len(ids), utils.commaAndify(ids))
|
||||
irc.reply(s)
|
||||
else:
|
||||
irc.reply('No dunnos found matching that search criteria.')
|
||||
search = wrap(search, ['channeldb', 'text'])
|
||||
|
||||
def get(self, irc, msg, args, channel, id):
|
||||
"""[<channel>] <id>
|
||||
|
||||
Display the text of the dunno with the given id. <channel> is only
|
||||
necessary if the message isn't sent in the channel itself.
|
||||
"""
|
||||
try:
|
||||
dunno = self.db.get(channel, id)
|
||||
name = ircdb.users.getUser(dunno.by).name
|
||||
at = time.localtime(dunno.at)
|
||||
timeStr = time.strftime(conf.supybot.humanTimestampFormat(), at)
|
||||
irc.reply("Dunno #%s: %s (added by %s at %s)" % \
|
||||
(id, utils.quoted(dunno.text), name, timeStr))
|
||||
except KeyError:
|
||||
irc.error('No dunno found with that id.')
|
||||
get = wrap(get, ['channeldb', ('id', 'dunno')])
|
||||
|
||||
def change(self, irc, msg, args, channel, id, replacer):
|
||||
"""[<channel>] <id> <regexp>
|
||||
|
||||
Alters the dunno with the given id according to the provided regexp.
|
||||
<channel> is only necessary if the message isn't sent in the channel
|
||||
itself.
|
||||
"""
|
||||
try:
|
||||
# Should this check that Record.by == user.id ||
|
||||
# checkChannelCapability like remove() does?
|
||||
self.db.change(channel, id, replacer)
|
||||
except KeyError:
|
||||
irc.error('There is no dunno #%s.' % id)
|
||||
return
|
||||
irc.replySuccess()
|
||||
change = wrap(change, ['channeldb', ('id', 'dunno'), 'regexpReplacer'])
|
||||
|
||||
def stats(self, irc, msg, args, channel):
|
||||
"""[<channel>]
|
||||
|
||||
Returns the number of dunnos in the dunno database. <channel> is only
|
||||
necessary if the message isn't sent in the channel itself.
|
||||
"""
|
||||
num = self.db.size(channel)
|
||||
irc.reply('There %s %s in my database.' %
|
||||
(utils.be(num), utils.nItems('dunno', num)))
|
||||
stats = wrap(stats, ['channeldb'])
|
||||
|
||||
|
||||
|
||||
Class = Dunno
|
||||
|
||||
|
@ -31,6 +31,8 @@
|
||||
Provides fun commands that require a database to operate.
|
||||
"""
|
||||
|
||||
deprecated = True
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import supybot.plugins as plugins
|
||||
|
118
plugins/Lart.py
Normal file
118
plugins/Lart.py
Normal file
@ -0,0 +1,118 @@
|
||||
###
|
||||
# Copyright (c) 2004, Jeremiah Fincher
|
||||
# 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.
|
||||
###
|
||||
|
||||
"""
|
||||
This plugin keeps a database of larts, and larts with it.
|
||||
"""
|
||||
|
||||
import supybot
|
||||
|
||||
__revision__ = "$Id$"
|
||||
__author__ = supybot.authors.jemfinch
|
||||
__contributors__ = {}
|
||||
|
||||
import re
|
||||
|
||||
import supybot.conf as conf
|
||||
import supybot.utils as utils
|
||||
from supybot.commands import *
|
||||
import supybot.plugins as plugins
|
||||
import supybot.ircutils as ircutils
|
||||
import supybot.privmsgs as privmsgs
|
||||
import supybot.registry as registry
|
||||
import supybot.callbacks as callbacks
|
||||
|
||||
|
||||
def configure(advanced):
|
||||
# This will be called by setup.py 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('Lart', True)
|
||||
|
||||
Lart = conf.registerPlugin('Lart')
|
||||
conf.registerChannelValue(Lart, 'showIds',
|
||||
registry.Boolean(False, """Determines whether the bot will show the ids of
|
||||
a lart when the lart is given."""))
|
||||
|
||||
class Lart(plugins.ChannelIdDatabasePlugin):
|
||||
_meRe = re.compile(r'\bme\b', re.I)
|
||||
_myRe = re.compile(r'\bmy\b', re.I)
|
||||
def _replaceFirstPerson(self, s, nick):
|
||||
s = self._meRe.sub(nick, s)
|
||||
s = self._myRe.sub('%s\'s' % nick, s)
|
||||
return s
|
||||
|
||||
def addValidator(self, irc, text):
|
||||
if '$who' not in text:
|
||||
irc.error('Larts must contain $who.', Raise=True)
|
||||
|
||||
def lart(self, irc, msg, args, channel, id, text):
|
||||
"""[<channel>] [<id>] <who|what> [for <reason>]
|
||||
|
||||
Uses the Luser Attitude Readjustment Tool on <who|what> (for <reason>,
|
||||
if given). If <id> is given, uses that specific lart. <channel> is
|
||||
only necessary if the message isn't sent in the channel itself.
|
||||
"""
|
||||
if ' for ' in text:
|
||||
(target, reason) = map(str.strip, text.split(' for ', 1))
|
||||
else:
|
||||
(target, reason) = (text, '')
|
||||
if ircutils.strEqual(target, irc.nick):
|
||||
target = msg.nick
|
||||
reason = 'trying to dis me'
|
||||
if id is not None:
|
||||
try:
|
||||
lart = self.db.get(channel, id)
|
||||
except KeyError:
|
||||
irc.error('There is no lart with id #%s.' % id)
|
||||
return
|
||||
else:
|
||||
lart = self.db.random(channel)
|
||||
if not lart:
|
||||
irc.error('There are no larts in my database for %s.' %channel)
|
||||
return
|
||||
text = self._replaceFirstPerson(lart.text, msg.nick)
|
||||
reason = self._replaceFirstPerson(reason, msg.nick)
|
||||
if target.endswith('.'):
|
||||
target = target.rstrip('.')
|
||||
target = self._replaceFirstPerson(target, msg.nick)
|
||||
text = text.replace('$who', target)
|
||||
if reason:
|
||||
text += ' for ' + reason
|
||||
if self.registryValue('showIds', channel):
|
||||
text += ' (#%s)' % lart.id
|
||||
irc.reply(text, action=True)
|
||||
lart = wrap(lart, ['channeldb', optional('id'), 'text'])
|
||||
|
||||
|
||||
Class = Lart
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
117
plugins/Praise.py
Normal file
117
plugins/Praise.py
Normal file
@ -0,0 +1,117 @@
|
||||
###
|
||||
# Copyright (c) 2004, Jeremiah Fincher
|
||||
# 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 the module docstring here. This will be used by the setup.py script.
|
||||
"""
|
||||
|
||||
import supybot
|
||||
|
||||
__revision__ = "$Id$"
|
||||
__author__ = supybot.authors.unknown
|
||||
__contributors__ = {}
|
||||
|
||||
import re
|
||||
|
||||
import supybot.conf as conf
|
||||
import supybot.utils as utils
|
||||
from supybot.commands import *
|
||||
import supybot.plugins as plugins
|
||||
import supybot.ircutils as ircutils
|
||||
import supybot.privmsgs as privmsgs
|
||||
import supybot.registry as registry
|
||||
import supybot.callbacks as callbacks
|
||||
|
||||
|
||||
def configure(advanced):
|
||||
# This will be called by setup.py 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('Praise', True)
|
||||
|
||||
|
||||
Praise = conf.registerPlugin('Praise')
|
||||
conf.registerChannelValue(Praise, 'showIds',
|
||||
registry.Boolean(False, """Determines whether the bot will show the ids of
|
||||
a praise when the praise is given."""))
|
||||
|
||||
class Praise(plugins.ChannelIdDatabasePlugin):
|
||||
_meRe = re.compile(r'\bme\b', re.I)
|
||||
_myRe = re.compile(r'\bmy\b', re.I)
|
||||
def _replaceFirstPerson(self, s, nick):
|
||||
s = self._meRe.sub(nick, s)
|
||||
s = self._myRe.sub('%s\'s' % nick, s)
|
||||
return s
|
||||
|
||||
def addValidator(self, irc, text):
|
||||
if '$who' not in text:
|
||||
irc.error('Praises must contain $who.', Raise=True)
|
||||
|
||||
def praise(self, irc, msg, args, channel, id, text):
|
||||
"""[<channel>] [<id>] <who|what> [for <reason>]
|
||||
|
||||
Praises <who|what> (for <reason>, if given). If <id> is given, uses
|
||||
that specific praise. <channel> is only necessary if the message isn't
|
||||
sent in the channel itself.
|
||||
"""
|
||||
if ' for ' in text:
|
||||
(target, reason) = map(str.strip, text.split(' for ', 1))
|
||||
else:
|
||||
(target, reason) = (text, '')
|
||||
if ircutils.strEqual(target, irc.nick):
|
||||
target = 'itself'
|
||||
if id is not None:
|
||||
try:
|
||||
praise = self.db.get(channel, id)
|
||||
except KeyError:
|
||||
irc.error('There is no praise with id #%s.' % id)
|
||||
return
|
||||
else:
|
||||
praise = self.db.random(channel)
|
||||
if not praise:
|
||||
irc.error('There are no praise in my database for %s.' %channel)
|
||||
return
|
||||
text = self._replaceFirstPerson(praise.text, msg.nick)
|
||||
reason = self._replaceFirstPerson(reason, msg.nick)
|
||||
if target.endswith('.'):
|
||||
target = target.rstrip('.')
|
||||
target = self._replaceFirstPerson(target, msg.nick)
|
||||
text = text.replace('$who', target)
|
||||
if reason:
|
||||
text += ' for ' + reason
|
||||
if self.registryValue('showIds', channel):
|
||||
text += ' (#%s)' % praise.id
|
||||
irc.reply(text, action=True)
|
||||
praise = wrap(praise, ['channeldb', optional('id'), 'text'])
|
||||
|
||||
Class = Praise
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
68
plugins/Quote.py
Normal file
68
plugins/Quote.py
Normal file
@ -0,0 +1,68 @@
|
||||
###
|
||||
# Copyright (c) 2002-2004, Jeremiah Fincher
|
||||
# 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.
|
||||
###
|
||||
|
||||
"""
|
||||
Maintains a Quotes database for each channel.
|
||||
"""
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import re
|
||||
import time
|
||||
import getopt
|
||||
import os.path
|
||||
|
||||
import supybot.dbi as dbi
|
||||
import supybot.conf as conf
|
||||
import supybot.utils as utils
|
||||
import supybot.ircdb as ircdb
|
||||
from supybot.commands import *
|
||||
import supybot.plugins as plugins
|
||||
import supybot.ircutils as ircutils
|
||||
import supybot.privmsgs as privmsgs
|
||||
import supybot.registry as registry
|
||||
import supybot.callbacks as callbacks
|
||||
|
||||
class Quotes(plugins.ChannelIdDatabasePlugin):
|
||||
def random(self, irc, msg, args, channel):
|
||||
"""[<channel>]
|
||||
|
||||
Returns a random quote from <channel>. <channel> is only necessary if
|
||||
the message isn't sent in the channel itself.
|
||||
"""
|
||||
quote = self.db.random(channel)
|
||||
if quote:
|
||||
irc.reply(self.showRecord(quote))
|
||||
else:
|
||||
irc.error('I have no quotes in my database for %s.' % channel)
|
||||
random = wrap(random, ['channeldb'])
|
||||
|
||||
|
||||
Class = Quotes
|
||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
@ -31,6 +31,8 @@
|
||||
Maintains a Quotes database for each channel.
|
||||
"""
|
||||
|
||||
deprecated = True
|
||||
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import re
|
||||
|
@ -54,31 +54,7 @@ conf.registerChannelValue(conf.supybot.plugins.Success, 'prefixNick',
|
||||
registry.Boolean(True, """Determines whether the bot will prefix the nick
|
||||
of the user giving an invalid command to the success response."""))
|
||||
|
||||
class DbiSuccessDB(plugins.DbiChannelDB):
|
||||
class DB(dbi.DB):
|
||||
class Record(dbi.Record):
|
||||
__fields__ = [
|
||||
'at',
|
||||
'by',
|
||||
'text',
|
||||
]
|
||||
def __init__(self, filename):
|
||||
# We use self.__class__ here because apparently DB isn't in our
|
||||
# scope. python--
|
||||
self.__parent = super(self.__class__, self)
|
||||
self.__parent.__init__(filename)
|
||||
|
||||
def add(self, text, by, at):
|
||||
return self.__parent.add(self.Record(at=at, by=by, text=text))
|
||||
|
||||
def change(self, id, f):
|
||||
dunno = self.get(id)
|
||||
dunno.text = f(dunno.text)
|
||||
self.set(id, dunno)
|
||||
|
||||
SuccessDB = plugins.DB('Success', {'flat': DbiSuccessDB})
|
||||
|
||||
class Success(callbacks.Privmsg):
|
||||
class Success(plugins.ChannelIdDatabasePlugin):
|
||||
"""This plugin was written initially to work with MoobotFactoids, the two
|
||||
of them to provide a similar-to-moobot-and-blootbot interface for factoids.
|
||||
Basically, it replaces the standard 'Error: <X> is not a valid command.'
|
||||
@ -88,7 +64,6 @@ class Success(callbacks.Privmsg):
|
||||
self.__parent = super(Success, self)
|
||||
self.__parent.__init__()
|
||||
self.target = None
|
||||
self.db = SuccessDB()
|
||||
pluginSelf = self
|
||||
self.originalClass = conf.supybot.replies.success.__class__
|
||||
class MySuccessClass(self.originalClass):
|
||||
@ -111,7 +86,6 @@ class Success(callbacks.Privmsg):
|
||||
conf.supybot.replies.success.__class__ = MySuccessClass
|
||||
|
||||
def die(self):
|
||||
self.db.close()
|
||||
self.__parent.die()
|
||||
conf.supybot.replies.success.__class__ = self.originalClass
|
||||
|
||||
@ -121,101 +95,6 @@ class Success(callbacks.Privmsg):
|
||||
self.target = msg.args[0]
|
||||
return msg
|
||||
|
||||
def add(self, irc, msg, args, user, at, channel, text):
|
||||
"""[<channel>] <text>
|
||||
|
||||
Adds <text> as a "success" to be used as a random response when a
|
||||
success message is needed. Can optionally contain '$who', which
|
||||
will be replaced by the user's name when the dunno is displayed.
|
||||
<channel> is only necessary if the message isn't sent in the channel
|
||||
itself.
|
||||
"""
|
||||
id = self.db.add(channel, text, user.id, at)
|
||||
irc.replySuccess('Success #%s added.' % id)
|
||||
add = wrap(add, ['user', 'now', 'channeldb', 'text'])
|
||||
|
||||
def remove(self, irc, msg, args, channel, id, user):
|
||||
"""[<channel>] <id>
|
||||
|
||||
Removes success with the given <id>. <channel> is only necessary if the
|
||||
message isn't sent in the channel itself.
|
||||
"""
|
||||
# Must be registered to use this
|
||||
try:
|
||||
success = self.db.get(channel, id)
|
||||
if user.id != success.by:
|
||||
cap = ircdb.makeChannelCapability(channel, 'op')
|
||||
if not ircdb.users.checkCapability(cap):
|
||||
irc.errorNoCapability(cap)
|
||||
self.db.remove(channel, id)
|
||||
irc.replySuccess()
|
||||
except KeyError:
|
||||
irc.error('No success has id #%s.' % id)
|
||||
remove = wrap(remove, ['channeldb', ('id', 'success'), 'user'])
|
||||
|
||||
def search(self, irc, msg, args, channel, text):
|
||||
"""[<channel>] <text>
|
||||
|
||||
Search for success containing the given text. Returns the ids of the
|
||||
successes with the text in them. <channel> is only necessary if the
|
||||
message isn't sent in the channel itself.
|
||||
"""
|
||||
def p(success):
|
||||
return text.lower() in success.text.lower()
|
||||
ids = [str(success.id) for success in self.db.select(channel, p)]
|
||||
if ids:
|
||||
s = 'Success search for %s (%s found): %s.' % \
|
||||
(utils.quoted(text), len(ids), utils.commaAndify(ids))
|
||||
irc.reply(s)
|
||||
else:
|
||||
irc.reply('No successes found matching that search criteria.')
|
||||
search = wrap(search, ['channeldb', 'text'])
|
||||
|
||||
def get(self, irc, msg, args, channel, id):
|
||||
"""[<channel>] <id>
|
||||
|
||||
Display the text of the success with the given id. <channel> is only
|
||||
necessary if the message isn't sent in the channel itself.
|
||||
"""
|
||||
try:
|
||||
success = self.db.get(channel, id)
|
||||
name = ircdb.users.getUser(success.by).name
|
||||
at = time.localtime(success.at)
|
||||
timeStr = time.strftime(conf.supybot.humanTimestampFormat(), at)
|
||||
irc.reply("Success #%s: %s (added by %s at %s)" % \
|
||||
(id, utils.quoted(success.text), name, timeStr))
|
||||
except KeyError:
|
||||
irc.error('No success found with that id.')
|
||||
get = wrap(get, ['channeldb', ('id', 'success')])
|
||||
|
||||
def change(self, irc, msg, args, user, channel, id, replacer):
|
||||
"""[<channel>] <id> <regexp>
|
||||
|
||||
Alters the success with the given id according to the provided regexp.
|
||||
<channel> is only necessary if the message isn't sent in the channel
|
||||
itself.
|
||||
"""
|
||||
try:
|
||||
self.db.change(channel, id, replacer)
|
||||
irc.replySuccess()
|
||||
except KeyError:
|
||||
irc.error('There is no success #%s.' % id)
|
||||
change = wrap(change, ['user', 'channeldb',
|
||||
('id', 'success'), 'regexpReplacer'])
|
||||
|
||||
|
||||
def stats(self, irc, msg, args, channel):
|
||||
"""[<channel>]
|
||||
|
||||
Returns the number of successes in the success database. <channel> is
|
||||
only necessary if the message isn't sent in the channel itself.
|
||||
"""
|
||||
num = self.db.size(channel)
|
||||
irc.reply('There %s %s in my database.' %
|
||||
(utils.be(num), utils.nItems('success', num)))
|
||||
stats = wrap(stats, ['channeldb'])
|
||||
|
||||
|
||||
|
||||
Class = Success
|
||||
|
||||
|
@ -40,15 +40,18 @@ import math
|
||||
import sets
|
||||
import time
|
||||
import random
|
||||
import fnmatch
|
||||
import os.path
|
||||
import UserDict
|
||||
import threading
|
||||
|
||||
import supybot.cdb as cdb
|
||||
import supybot.log as log
|
||||
import supybot.dbi as dbi
|
||||
import supybot.conf as conf
|
||||
import supybot.ircdb as ircdb
|
||||
import supybot.utils as utils
|
||||
import supybot.world as world
|
||||
from supybot.commands import *
|
||||
import supybot.ircutils as ircutils
|
||||
import supybot.webutils as webutils
|
||||
import supybot.callbacks as callbacks
|
||||
@ -194,7 +197,7 @@ class ChannelDBHandler(object):
|
||||
|
||||
def makeDb(self, filename):
|
||||
"""Override this to create your databases."""
|
||||
return cdb.shelf(filename)
|
||||
raise NotImplementedError
|
||||
|
||||
def getDb(self, channel):
|
||||
"""Use this to get a database for a specific channel."""
|
||||
@ -352,12 +355,173 @@ class ChannelUserDB(ChannelUserDictionary):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
## class ChannelIdDatabasePlugin(callbacks.Privmsg):
|
||||
## def __init__(self):
|
||||
## # XXX Register configuration variables.
|
||||
## self.__parent = super(ChannelIdDatabasePlugin, self)
|
||||
## self.__parent.__init__(self)
|
||||
## self.db = self.DB()
|
||||
class ChannelIdDatabasePlugin(callbacks.Privmsg):
|
||||
class DB(DbiChannelDB):
|
||||
class DB(dbi.DB):
|
||||
class Record(dbi.Record):
|
||||
__fields__ = [
|
||||
'at',
|
||||
'by',
|
||||
'text'
|
||||
]
|
||||
def add(self, at, by, text, **kwargs):
|
||||
record = self.Record(at=at, by=by, text=text, **kwargs)
|
||||
return super(self.__class__, self).add(record)
|
||||
|
||||
def __init__(self):
|
||||
self.__parent = super(ChannelIdDatabasePlugin, self)
|
||||
self.__parent.__init__()
|
||||
self.db = DB(self.name(), {'flat': self.DB})()
|
||||
|
||||
def die(self):
|
||||
self.db.close()
|
||||
self.__parent.die()
|
||||
|
||||
def getCommandHelp(self, name):
|
||||
help = self.__parent.getCommandHelp(name)
|
||||
help = help.replace('$Types', utils.pluralize(self.name()))
|
||||
help = help.replace('$Type', self.name())
|
||||
help = help.replace('$types', utils.pluralize(self.name().lower()))
|
||||
help = help.replace('$type', self.name().lower())
|
||||
return help
|
||||
|
||||
def noSuchRecord(self, irc, channel, id):
|
||||
irc.error('There is no %s with id #%s in my database for %s.' %
|
||||
(self.name(), id, channel))
|
||||
|
||||
def checkChangeAllowed(self, irc, msg, channel, user, record):
|
||||
if user.id == record.by:
|
||||
return True
|
||||
cap = ircdb.makeChannelCapability(channel, 'op')
|
||||
if ircdb.checkCapability(msg.prefix, cap):
|
||||
return True
|
||||
irc.errorNoCapability(cap)
|
||||
|
||||
def addValidator(self, irc, text):
|
||||
"""This should irc.error or raise an exception if text is invalid."""
|
||||
pass
|
||||
|
||||
def add(self, irc, msg, args, user, channel, text):
|
||||
"""[<channel>] <text>
|
||||
|
||||
Adds <text> to the $type database for <channel>.
|
||||
<channel> is only necessary if the message isn't sent in the channel
|
||||
itself.
|
||||
"""
|
||||
at = time.time()
|
||||
self.addValidator(irc, text)
|
||||
if text is not None:
|
||||
id = self.db.add(channel, at, user.id, text)
|
||||
irc.replySuccess('%s #%s added.' % (self.name(), id))
|
||||
add = wrap(add, ['user', 'channeldb', 'text'])
|
||||
|
||||
def remove(self, irc, msg, args, user, channel, id):
|
||||
"""[<channel>] <id>
|
||||
|
||||
Removes the $type with id <id> from the $type database for <channel>.
|
||||
<channel> is only necessary if the message isn't sent in the channel
|
||||
itself.
|
||||
"""
|
||||
try:
|
||||
record = self.db.get(channel, id)
|
||||
self.checkChangeAllowed(irc, msg, channel, user, record)
|
||||
self.db.remove(channel, id)
|
||||
irc.replySuccess()
|
||||
except KeyError:
|
||||
self.noSuchRecord(irc, channel, id)
|
||||
remove = wrap(remove, ['user', 'channeldb', 'id'])
|
||||
|
||||
def searchSerializeRecord(self, record):
|
||||
text = utils.quoted(utils.ellipsisify(record.text, 50))
|
||||
return '#%s: %s' % (record.id, text)
|
||||
|
||||
def search(self, irc, msg, args, channel, optlist, glob):
|
||||
"""[<channel>] [--{regexp,by} <value>] [<glob>]
|
||||
|
||||
Searches for $types matching the criteria given. XXX
|
||||
"""
|
||||
predicates = []
|
||||
def p(record):
|
||||
for predicate in predicates:
|
||||
if not predicate(record):
|
||||
return False
|
||||
return True
|
||||
|
||||
for (opt, arg) in optlist:
|
||||
if opt == 'by':
|
||||
predicates.append(lambda r, arg=arg: r.by == arg.id)
|
||||
elif opt == 'regexp':
|
||||
predicates.append(lambda r, arg=arg: arg.search(r.text))
|
||||
if glob:
|
||||
# XXX Case sensitive.
|
||||
predicates.append(lambda r: fnmatch.fnmatch(r.text, glob))
|
||||
L = []
|
||||
for record in self.db.select(channel, p):
|
||||
L.append(self.searchSerializeRecord(record))
|
||||
if L:
|
||||
L.sort()
|
||||
irc.reply(utils.commaAndify(L))
|
||||
else:
|
||||
irc.reply('No matching %s were found.' %
|
||||
utils.pluralize(self.name().lower()))
|
||||
search = wrap(search, ['channeldb',
|
||||
getopts({'by': 'otherUser',
|
||||
'regexp': 'regexpMatcher'}),
|
||||
additional(rest('glob'))])
|
||||
|
||||
def showRecord(self, record):
|
||||
try:
|
||||
name = ircdb.users.getUser(record.by).name
|
||||
except KeyError:
|
||||
name = 'a user that is no longer registered'
|
||||
at = time.localtime(record.at)
|
||||
timeS = time.strftime(conf.supybot.humanTimestampFormat(), at)
|
||||
return '%s #%S: %s (added by %s at %s)' % \
|
||||
(self.name(), record.id, utils.quoted(record.text), name, timeS)
|
||||
|
||||
def get(self, irc, msg, args, channel, id):
|
||||
"""[<channel>] <id>
|
||||
|
||||
Gets the $type with id <id> from the $type database for <channel>.
|
||||
<channel> is only necessary if the message isn't sent in the channel
|
||||
itself.
|
||||
"""
|
||||
try:
|
||||
record = self.db.get(channel, id)
|
||||
irc.reply(self.showRecord(record))
|
||||
except KeyError:
|
||||
self.noSuchRecord(irc, channel, id)
|
||||
get = wrap(get, ['channeldb', 'id'])
|
||||
|
||||
def change(self, irc, msg, args, user, channel, id, replacer):
|
||||
"""[<channel>] <id> <regexp>
|
||||
|
||||
Changes the $type with id <id> according to the regular expression
|
||||
<regexp>. <channel> is only necessary if the message isn't sent in the
|
||||
channel itself.
|
||||
"""
|
||||
try:
|
||||
record = self.db.get(channel, id)
|
||||
self.checkChangeAllowed(irc, msg, channel, user, record)
|
||||
record.text = replacer(record.text)
|
||||
self.db.set(channel, id, record)
|
||||
irc.replySuccess()
|
||||
except KeyError:
|
||||
self.noSuchRecord(irc, channel, id)
|
||||
change = wrap(change, ['user', 'channeldb', 'id', 'regexpReplacer'])
|
||||
|
||||
def stats(self, irc, msg, args, channel):
|
||||
"""[<channel>]
|
||||
|
||||
Returns the number of $types in the database for <channel>.
|
||||
<channel> is only necessary if the message isn't sent in the channel
|
||||
itself.
|
||||
"""
|
||||
n = self.db.size(channel)
|
||||
irc.reply('There %s %s in my database.' %
|
||||
(utils.be(n), utils.nItems(self.name().lower(), n)))
|
||||
stats = wrap(stats, ['channeldb'])
|
||||
|
||||
|
||||
class PeriodicFileDownloader(object):
|
||||
"""A class to periodically download a file/files.
|
||||
|
Loading…
Reference in New Issue
Block a user