From d844b1d19ceea0ec516d06e6508c7030edb45637 Mon Sep 17 00:00:00 2001 From: GLolol Date: Wed, 4 Feb 2015 21:10:18 -0800 Subject: [PATCH 1/7] Admin: allow specifying a default part message in plugins.admin.partmsg (Closes ProgVal#391) Cherry-picked from commit GLolol@f69c789. --- plugins/Admin/config.py | 9 ++++++--- plugins/Admin/plugin.py | 8 ++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/plugins/Admin/config.py b/plugins/Admin/config.py index 49a018483..bab52ad1e 100644 --- a/plugins/Admin/config.py +++ b/plugins/Admin/config.py @@ -43,8 +43,11 @@ def configure(advanced): Admin = conf.registerPlugin('Admin') -# This is where your configuration variables (if any) should go. For example: -# conf.registerGlobalValue(Admin, 'someConfigVariableName', -# registry.Boolean(False, """Help for someConfigVariableName.""")) + +conf.registerChannelValue(Admin, 'partMsg', + registry.String('%version%', _("""Determines what part message should be + used by default. If the part command is called without a part message, + this will be used. If this value is empty, then no part message will + be used (they are optional in the IRC protocol)."""))) # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Admin/plugin.py b/plugins/Admin/plugin.py index 44e5a437d..fe9281f5a 100644 --- a/plugins/Admin/plugin.py +++ b/plugins/Admin/plugin.py @@ -238,7 +238,9 @@ class Admin(callbacks.Plugin): Tells the bot to part the list of channels you give it. is only necessary if you want the bot to part a channel other than the current channel. If is specified, use it as the part - message. + message. Otherwise, the default part message specified in + supybot.plugins.Admin.partMsg will be used. No part message will be + used if no default is configured. """ if channel is None: if irc.isChannel(msg.args[0]): @@ -252,7 +254,9 @@ class Admin(callbacks.Plugin): pass if channel not in irc.state.channels: irc.error(_('I\'m not in %s.') % channel, Raise=True) - irc.queueMsg(ircmsgs.part(channel, reason or msg.nick)) + reason = (reason or self.registryValue("partMsg", channel)) + reason = reason.replace("%version%", "Supybot %s" % conf.version) + irc.queueMsg(ircmsgs.part(channel, reason)) if msg.nick in irc.state.channels[channel].users: irc.noReply() else: From 0e0feb1a8489638c8fc7dfa9a189cba6111db471 Mon Sep 17 00:00:00 2001 From: James Lu Date: Wed, 4 Feb 2015 21:20:45 -0800 Subject: [PATCH 2/7] Owner: substitute %version% for the Supybot version in plugins.Owner.quitMsg (Closes ProgVal#847) Cherry-picked from commit GLolol@205199e. --- plugins/Owner/config.py | 4 ++-- plugins/Owner/plugin.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/Owner/config.py b/plugins/Owner/config.py index 25e5d9915..02852e5b4 100644 --- a/plugins/Owner/config.py +++ b/plugins/Owner/config.py @@ -46,10 +46,10 @@ conf.registerGlobalValue(Owner, 'public', registry.Boolean(True, """Determines whether this plugin is publicly visible.""")) conf.registerGlobalValue(Owner, 'quitMsg', - registry.String('', """Determines what quit message will be used by default. + registry.String('%version%', """Determines what quit message will be used by default. If the quit command is called without a quit message, this will be used. If this value is empty, the nick of the person giving the quit command will be - used.""")) + used. %version% is automatically expanded to the bot's current version.""")) conf.registerGroup(conf.supybot.commands, 'renames', orderAlphabetically=True) diff --git a/plugins/Owner/plugin.py b/plugins/Owner/plugin.py index 8f5afc245..e3ed912ea 100644 --- a/plugins/Owner/plugin.py +++ b/plugins/Owner/plugin.py @@ -344,9 +344,11 @@ class Owner(callbacks.Plugin): Exits the bot with the QUIT message . If is not given, the default quit message (supybot.plugins.Owner.quitMsg) will be used. - If there is no default quitMsg set, your nick will be used. + If there is no default quitMsg set, your nick will be used. %version% + is automatically expanded to the bot's current version. """ text = text or self.registryValue('quitMsg') or msg.nick + text = text.replace("%version%", "Supybot %s" % conf.version) irc.noReply() m = ircmsgs.quit(text) world.upkeep() From b243c83e4127efdd2e714fb76aae3316fc6b96da Mon Sep 17 00:00:00 2001 From: James Lu Date: Thu, 5 Feb 2015 20:26:14 -0800 Subject: [PATCH 3/7] Admin/Owner: Use standard substitution for part/quit messages --- plugins/Admin/config.py | 5 +++-- plugins/Admin/plugin.py | 2 +- plugins/Owner/config.py | 5 +++-- plugins/Owner/plugin.py | 6 +++--- src/ircutils.py | 3 ++- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/plugins/Admin/config.py b/plugins/Admin/config.py index bab52ad1e..86023660e 100644 --- a/plugins/Admin/config.py +++ b/plugins/Admin/config.py @@ -45,9 +45,10 @@ def configure(advanced): Admin = conf.registerPlugin('Admin') conf.registerChannelValue(Admin, 'partMsg', - registry.String('%version%', _("""Determines what part message should be + registry.String('$version', _("""Determines what part message should be used by default. If the part command is called without a part message, this will be used. If this value is empty, then no part message will - be used (they are optional in the IRC protocol)."""))) + be used (they are optional in the IRC protocol). The standard + substitutions ($version, $nick, etc.) are all handled appropriately."""))) # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Admin/plugin.py b/plugins/Admin/plugin.py index fe9281f5a..634a0ede2 100644 --- a/plugins/Admin/plugin.py +++ b/plugins/Admin/plugin.py @@ -255,7 +255,7 @@ class Admin(callbacks.Plugin): if channel not in irc.state.channels: irc.error(_('I\'m not in %s.') % channel, Raise=True) reason = (reason or self.registryValue("partMsg", channel)) - reason = reason.replace("%version%", "Supybot %s" % conf.version) + reason = ircutils.standardSubstitute(irc, msg, reason) irc.queueMsg(ircmsgs.part(channel, reason)) if msg.nick in irc.state.channels[channel].users: irc.noReply() diff --git a/plugins/Owner/config.py b/plugins/Owner/config.py index 02852e5b4..243e4ee07 100644 --- a/plugins/Owner/config.py +++ b/plugins/Owner/config.py @@ -46,10 +46,11 @@ conf.registerGlobalValue(Owner, 'public', registry.Boolean(True, """Determines whether this plugin is publicly visible.""")) conf.registerGlobalValue(Owner, 'quitMsg', - registry.String('%version%', """Determines what quit message will be used by default. + registry.String('$version', """Determines what quit message will be used by default. If the quit command is called without a quit message, this will be used. If this value is empty, the nick of the person giving the quit command will be - used. %version% is automatically expanded to the bot's current version.""")) + used. The standard substitutions ($version, $nick, etc.) are all handled + appropriately.""")) conf.registerGroup(conf.supybot.commands, 'renames', orderAlphabetically=True) diff --git a/plugins/Owner/plugin.py b/plugins/Owner/plugin.py index e3ed912ea..dc8de8981 100644 --- a/plugins/Owner/plugin.py +++ b/plugins/Owner/plugin.py @@ -344,11 +344,11 @@ class Owner(callbacks.Plugin): Exits the bot with the QUIT message . If is not given, the default quit message (supybot.plugins.Owner.quitMsg) will be used. - If there is no default quitMsg set, your nick will be used. %version% - is automatically expanded to the bot's current version. + If there is no default quitMsg set, your nick will be used. The standard + substitutions ($version, $nick, etc.) are all handled appropriately. """ text = text or self.registryValue('quitMsg') or msg.nick - text = text.replace("%version%", "Supybot %s" % conf.version) + text = ircutils.standardSubstitute(irc, msg, text) irc.noReply() m = ircmsgs.quit(text) world.upkeep() diff --git a/src/ircutils.py b/src/ircutils.py index 9768e676d..49caf9d06 100644 --- a/src/ircutils.py +++ b/src/ircutils.py @@ -49,7 +49,7 @@ from cStringIO import StringIO as sio from . import utils from . import minisix - +from .version import version def debug(s, *args): """Prints a debug string. Most likely replaced by our logging debug.""" @@ -713,6 +713,7 @@ def standardSubstitute(irc, msg, text, env=None): 'm': localtime[4], 'min': localtime[4], 'minute': localtime[4], 's': localtime[5], 'sec': localtime[5], 'second': localtime[5], 'tz': time.strftime('%Z', localtime), + 'version': 'Supybot %s' % version, }) if msg.reply_env: vars.update(msg.reply_env) From 0c85c6d796d7dbc16a9908108c8e60f55ae5f8eb Mon Sep 17 00:00:00 2001 From: James Lu Date: Thu, 5 Feb 2015 22:30:18 -0800 Subject: [PATCH 4/7] supybot: also expand substitutes when exiting on Ctrl-C --- scripts/supybot | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/supybot b/scripts/supybot index 00ebd9bf2..41ca10d78 100644 --- a/scripts/supybot +++ b/scripts/supybot @@ -69,6 +69,7 @@ import supybot.i18n as i18n import supybot.utils as utils import supybot.registry as registry import supybot.questions as questions +import supybot.ircutils as ircutils from supybot.version import version @@ -104,6 +105,8 @@ def main(): for irc in world.ircs: quitmsg = conf.supybot.plugins.Owner.quitMsg() or \ 'Ctrl-C at console.' + msg = ircmsgs.ping('Ctrl-C at console.') + quitmsg = ircutils.standardSubstitute(irc, msg, quitmsg) irc.queueMsg(ircmsgs.quit(quitmsg)) irc.die() except SystemExit as e: From 59b39ea45ebf4fa5f52e64d173d0af9f9077b821 Mon Sep 17 00:00:00 2001 From: James Lu Date: Sat, 7 Feb 2015 10:01:47 -0800 Subject: [PATCH 5/7] scripts/supybot: use None as msg for standardSubstitute on Ctrl-C --- scripts/supybot | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/supybot b/scripts/supybot index 41ca10d78..a658ea78a 100644 --- a/scripts/supybot +++ b/scripts/supybot @@ -105,8 +105,7 @@ def main(): for irc in world.ircs: quitmsg = conf.supybot.plugins.Owner.quitMsg() or \ 'Ctrl-C at console.' - msg = ircmsgs.ping('Ctrl-C at console.') - quitmsg = ircutils.standardSubstitute(irc, msg, quitmsg) + quitmsg = ircutils.standardSubstitute(irc, None, quitmsg) irc.queueMsg(ircmsgs.quit(quitmsg)) irc.die() except SystemExit as e: From a67fb94875cb48d3c5a9c90861e60d4aedbbbb02 Mon Sep 17 00:00:00 2001 From: James Lu Date: Fri, 27 Feb 2015 18:11:10 -0800 Subject: [PATCH 6/7] Move 'part' command from Admin to Channel and require #channel,op instead of admin Closes #79. --- plugins/Admin/config.py | 4 ---- plugins/Admin/plugin.py | 27 --------------------------- plugins/Admin/test.py | 21 --------------------- plugins/Channel/config.py | 7 ++++++- plugins/Channel/plugin.py | 35 +++++++++++++++++++++++++++++++++++ plugins/Channel/test.py | 23 ++++++++++++++++++++++- 6 files changed, 63 insertions(+), 54 deletions(-) diff --git a/plugins/Admin/config.py b/plugins/Admin/config.py index 49a018483..0a6f64211 100644 --- a/plugins/Admin/config.py +++ b/plugins/Admin/config.py @@ -41,10 +41,6 @@ def configure(advanced): from supybot.questions import expect, anything, something, yn conf.registerPlugin('Admin', True) - Admin = conf.registerPlugin('Admin') -# This is where your configuration variables (if any) should go. For example: -# conf.registerGlobalValue(Admin, 'someConfigVariableName', -# registry.Boolean(False, """Help for someConfigVariableName.""")) # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Admin/plugin.py b/plugins/Admin/plugin.py index 44e5a437d..cd18a6a84 100644 --- a/plugins/Admin/plugin.py +++ b/plugins/Admin/plugin.py @@ -232,33 +232,6 @@ class Admin(callbacks.Plugin): nick = wrap(nick, [additional('nick'), additional('something')]) @internationalizeDocstring - def part(self, irc, msg, args, channel, reason): - """[] [] - - Tells the bot to part the list of channels you give it. is - only necessary if you want the bot to part a channel other than the - current channel. If is specified, use it as the part - message. - """ - if channel is None: - if irc.isChannel(msg.args[0]): - channel = msg.args[0] - else: - irc.error(Raise=True) - try: - network = conf.supybot.networks.get(irc.network) - network.channels().remove(channel) - except KeyError: - pass - if channel not in irc.state.channels: - irc.error(_('I\'m not in %s.') % channel, Raise=True) - irc.queueMsg(ircmsgs.part(channel, reason or msg.nick)) - if msg.nick in irc.state.channels[channel].users: - irc.noReply() - else: - irc.replySuccess() - part = wrap(part, [optional('validChannel'), additional('text')]) - class capability(callbacks.Commands): @internationalizeDocstring diff --git a/plugins/Admin/test.py b/plugins/Admin/test.py index 5f94faf6f..6c090daef 100644 --- a/plugins/Admin/test.py +++ b/plugins/Admin/test.py @@ -94,27 +94,6 @@ class AdminTestCase(PluginTestCase): self.assertEqual(m.args[0], '#foo') self.assertEqual(m.args[1], 'key') - def testPart(self): - def getAfterJoinMessages(): - m = self.irc.takeMsg() - self.assertEqual(m.command, 'MODE') - m = self.irc.takeMsg() - self.assertEqual(m.command, 'MODE') - m = self.irc.takeMsg() - self.assertEqual(m.command, 'WHO') - self.assertError('part #foo') - self.assertRegexp('part #foo', 'not in') - self.irc.feedMsg(ircmsgs.join('#foo', prefix=self.prefix)) - getAfterJoinMessages() - m = self.getMsg('part #foo') - self.assertEqual(m.command, 'PART') - self.irc.feedMsg(ircmsgs.join('#foo', prefix=self.prefix)) - getAfterJoinMessages() - m = self.getMsg('part #foo reason') - self.assertEqual(m.command, 'PART') - self.assertEqual(m.args[0], '#foo') - self.assertEqual(m.args[1], 'reason') - def testNick(self): original = conf.supybot.nick() try: diff --git a/plugins/Channel/config.py b/plugins/Channel/config.py index 19f7462be..bccdb28f0 100644 --- a/plugins/Channel/config.py +++ b/plugins/Channel/config.py @@ -51,6 +51,11 @@ conf.registerChannelValue(Channel, 'nicksInPrivate', registry.Boolean(True, _("""Determines whether the output of 'nicks' will be sent in private. This prevents mass-highlights of a channel's users, accidental or on purpose."""))) - +conf.registerChannelValue(Channel, 'partMsg', + registry.String('$version', _("""Determines what part message should be + used by default. If the part command is called without a part message, + this will be used. If this value is empty, then no part message will + be used (they are optional in the IRC protocol). The standard + substitutions ($version, $nick, etc.) are all handled appropriately."""))) # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Channel/plugin.py b/plugins/Channel/plugin.py index 75834daa2..1450fdfb6 100644 --- a/plugins/Channel/plugin.py +++ b/plugins/Channel/plugin.py @@ -941,6 +941,41 @@ class Channel(callbacks.Plugin): self.alertOps(irc, channel, text, frm=msg.nick) alert = wrap(alert, ['inChannel', 'text']) + @internationalizeDocstring + def part(self, irc, msg, args, channel, reason): + """[] [] + + Tells the bot to part the list of channels you give it. is + only necessary if you want the bot to part a channel other than the + current channel. If is specified, use it as the part + message. Otherwise, the default part message specified in + supybot.plugins.Channel.partMsg will be used. No part message will be + used if no default is configured. + """ + if channel is None: + if irc.isChannel(msg.args[0]): + channel = msg.args[0] + else: + irc.error(Raise=True) + capability = ircdb.makeChannelCapability(channel, 'op') + hostmask = irc.state.nickToHostmask(msg.nick) + if not ircdb.checkCapability(hostmask, capability): + irc.errorNoCapability(capability, Raise=True) + try: + network = conf.supybot.networks.get(irc.network) + network.channels().remove(channel) + except KeyError: + pass + if channel not in irc.state.channels: + irc.error(_('I\'m not in %s.') % channel, Raise=True) + reason = (reason or self.registryValue("partMsg", channel)) + reason = ircutils.standardSubstitute(irc, msg, reason) + irc.queueMsg(ircmsgs.part(channel, reason)) + if msg.nick in irc.state.channels[channel].users: + irc.noReply() + else: + irc.replySuccess() + part = wrap(part, [optional('validChannel'), additional('text')]) Class = Channel diff --git a/plugins/Channel/test.py b/plugins/Channel/test.py index 6a8e4568e..2ac9bc148 100644 --- a/plugins/Channel/test.py +++ b/plugins/Channel/test.py @@ -251,6 +251,27 @@ class ChannelTestCase(ChannelPluginTestCase): def testNicks(self): self.assertResponse('channel nicks', 'bar, foo, and test') self.assertResponse('channel nicks --count', '3') - + + def testPart(self): + def getAfterJoinMessages(): + m = self.irc.takeMsg() + self.assertEqual(m.command, 'MODE') + m = self.irc.takeMsg() + self.assertEqual(m.command, 'MODE') + m = self.irc.takeMsg() + self.assertEqual(m.command, 'WHO') + self.assertError('part #foo') + self.assertRegexp('part #foo', 'not in') + self.irc.feedMsg(ircmsgs.join('#foo', prefix=self.prefix)) + getAfterJoinMessages() + m = self.getMsg('part #foo') + self.assertEqual(m.command, 'PART') + self.irc.feedMsg(ircmsgs.join('#foo', prefix=self.prefix)) + getAfterJoinMessages() + m = self.getMsg('part #foo reason') + self.assertEqual(m.command, 'PART') + self.assertEqual(m.args[0], '#foo') + self.assertEqual(m.args[1], 'reason') + # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: From 32988ee3a3d59f723d850485196cc9ff9e28baa1 Mon Sep 17 00:00:00 2001 From: James Lu Date: Fri, 27 Feb 2015 18:27:58 -0800 Subject: [PATCH 7/7] Channel.cycle: allow specifying part message + defaults to plugins.Channel.partMsg Closes #1062. --- plugins/Channel/plugin.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/Channel/plugin.py b/plugins/Channel/plugin.py index 1450fdfb6..d4e425013 100644 --- a/plugins/Channel/plugin.py +++ b/plugins/Channel/plugin.py @@ -258,17 +258,22 @@ class Channel(callbacks.Plugin): any('nickInChannel')]) @internationalizeDocstring - def cycle(self, irc, msg, args, channel): + def cycle(self, irc, msg, args, channel, reason): """[] If you have the #channel,op capability, this will cause the bot to "cycle", or PART and then JOIN the channel. is only necessary - if the message isn't sent in the channel itself. + if the message isn't sent in the channel itself. If is not + specified, the default part message specified in + supybot.plugins.Channel.partMsg will be used. No part message will be + used if neither a cycle reason nor a default part message is given. """ - self._sendMsg(irc, ircmsgs.part(channel, msg.nick)) + reason = (reason or self.registryValue("partMsg", channel)) + reason = ircutils.standardSubstitute(irc, msg, reason) + self._sendMsg(irc, ircmsgs.part(channel, reason)) networkGroup = conf.supybot.networks.get(irc.network) self._sendMsg(irc, networkGroup.channels.join(channel)) - cycle = wrap(cycle, ['op']) + cycle = wrap(cycle, ['op', additional('text')]) @internationalizeDocstring def kick(self, irc, msg, args, channel, nicks, reason):