diff --git a/pyircbot/common.py b/pyircbot/common.py index f77c7ef..58b9318 100644 --- a/pyircbot/common.py +++ b/pyircbot/common.py @@ -74,26 +74,36 @@ class TouchReload(Thread): sleep(self.sleep) -def messageHasCommand(command, message, requireArgs=False): - """Check if a message has a command with or without args in it +def messageHasCommand(command, message, requireArgs=False, withHighlight=False): + """ + Check if a message has a command with or without args in it :param command: the command string to look for, like !ban. If a list is passed, the first match is returned. :type command: str or list :param message: the message string to look in, like "!ban Lil_Mac" :type message: str - :param requireArgs: if true, only validate if the command use has any amount of trailing text - :type requireArgs: bool""" + :param requireArgs: only match if trailing data is passed with the command used. False-like values disable This + requirement. True-like values require any number of args greater than one. Int values require a specific number + of args + :type requireArgs: bool + :param withHighlight: if provided, treat 'Nick[:,] command args' the same as '.command args' where Nick is a string + provided by withHighlight + :type withHighlight: str + """ if not type(command) == list: command = [command] for item in command: - cmd = messageHasCommandSingle(item, message, requireArgs) + cmd = messageHasCommandSingle(item, message, requireArgs, withHighlight) if cmd: return cmd return False -def messageHasCommandSingle(command, message, requireArgs=False): +def messageHasCommandSingle(command, message, requireArgs=False, withHighlight=False): + if withHighlight: + if message.startswith(withHighlight + ": ") or message.startswith(withHighlight + ", "): + message = "." + message[len(withHighlight) + 2:] # Check if the message at least starts with the command messageBeginning = message[0:len(command)] if messageBeginning != command: @@ -108,13 +118,16 @@ def messageHasCommandSingle(command, message, requireArgs=False): args = "" if argsStart > 0: args = message[argsStart + 1:].strip() - - if requireArgs and args == '': - return False + args_list = args.split() + if requireArgs: + if args == '': + return False + elif type(requireArgs) is int and len(args_list) != requireArgs: + return False # Verified! Return the set. return ParsedCommand(command, - args.split(" ") if args else [], + args_list, args, message) diff --git a/pyircbot/irccore.py b/pyircbot/irccore.py index c366af5..8702696 100644 --- a/pyircbot/irccore.py +++ b/pyircbot/irccore.py @@ -58,6 +58,8 @@ class IRCCore(object): self.bind_addr = None """Optionally bind to a specific address. This should be a (host, port) tuple.""" + self.nick = None + # Set up hooks for modules self.initHooks() diff --git a/pyircbot/modulebase.py b/pyircbot/modulebase.py index 883bfe1..56706fc 100644 --- a/pyircbot/modulebase.py +++ b/pyircbot/modulebase.py @@ -197,10 +197,13 @@ class command(hook): :param keywords: commands to listen for :type keywords: str - :param require_args: only match if trailing data is passed with the command used - :type require_args: bool + :param require_args: only match if trailing data is passed with the command used. False-like values disable This + requirement. True-like values require any number of args greater than one. Int values require a specific + number of args + :type require_args: bool, int :param allow_private: enable matching in private messages :type allow_private: bool + :param allow_highlight: treat 'Nick[:,] command args' the same as '.command args' """ prefix = "." @@ -208,12 +211,12 @@ class command(hook): Hotkey that must appear before commands """ - def __init__(self, *keywords, require_args=False, allow_private=False): + def __init__(self, *keywords, require_args=False, allow_private=False, allow_highlight=True): super().__init__("PRIVMSG") self.keywords = keywords self.require_args = require_args self.allow_private = allow_private - self.parsed_cmd = None + self.allow_highlight = allow_highlight def validate(self, msg, bot): """ @@ -224,19 +227,23 @@ class command(hook): :param bot: reference to main pyircbot :type bot: pyircbot.pyircbot.PyIRCBot """ + bot_nick = bot.get_nick() if not super().validate(msg, bot): return False if msg.args[0][0] != "#" and not self.allow_private: return False for keyword in self.keywords: - single = self._validate_one(msg, keyword) + single = self._validate_prefixedcommand(msg, keyword, bot_nick) if single: + print(single) return single return False - def _validate_one(self, msg, keyword): + def _validate_prefixedcommand(self, msg, keyword, nick): with_prefix = "{}{}".format(self.prefix, keyword) - return messageHasCommand(with_prefix, msg.trailing, requireArgs=self.require_args) + return messageHasCommand(with_prefix, msg.trailing, + requireArgs=self.require_args, + withHighlight=nick if self.allow_highlight else False) class regex(hook): diff --git a/pyircbot/modules/CryptoWallet.py b/pyircbot/modules/CryptoWallet.py index 62c50ca..5ccc50a 100755 --- a/pyircbot/modules/CryptoWallet.py +++ b/pyircbot/modules/CryptoWallet.py @@ -9,7 +9,6 @@ from pyircbot.modulebase import ModuleBase, command from pyircbot.modules.ModInfo import info -from pyircbot.common import messageHasCommand from decimal import Decimal import time import hashlib diff --git a/pyircbot/modules/LMGTFY.py b/pyircbot/modules/LMGTFY.py index 68e46a0..882b041 100644 --- a/pyircbot/modules/LMGTFY.py +++ b/pyircbot/modules/LMGTFY.py @@ -18,16 +18,8 @@ class LMGTFY(ModuleBase): @info("lmgtfy display a condescending internet query", cmds=["lmgtfy"]) @command("lmgtfy", require_args=True) def handleMessage(self, msg, cmd): - message = msg.trailing.split(" ")[1:] - link = self.createLink(message) - self.bot.act_PRIVMSG(msg.args[0], "%s: %s" % (msg.prefix.nick, link)) + link = self.createLink(cmd.args_str) + self.bot.act_PRIVMSG(msg.args[0], "{}: {}".format(msg.prefix.nick, link)) def createLink(self, message): - finalUrl = BASE_URL - - for word in message: - finalUrl += urllib.parse.quote(word) - if word != message[-1]: - finalUrl += "+" - - return finalUrl + return BASE_URL + "+".join([urllib.parse.quote(word) for word in message.split()]) diff --git a/run-tests.sh b/run-tests.sh index 9658c96..6a304de 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -3,4 +3,4 @@ export PYTHONUNBUFFERED=1 export PYTHONPATH=. -py.test --fulltrace --cov=pyircbot --cov-report html -n 4 tests/ +py.test --fulltrace --cov=pyircbot --cov-report html -n 4 tests/ $@ diff --git a/tests/lib.py b/tests/lib.py index 990d994..726f969 100644 --- a/tests/lib.py +++ b/tests/lib.py @@ -50,6 +50,9 @@ class FakeBaseBot(PrimitiveBot): super().unloadmodule(module_name) self._modules.remove(module_name) + def get_nick(self): + return "testbot" + @pytest.fixture def fakebot(tmpdir): diff --git a/tests/modules/test_lmgtfy.py b/tests/modules/test_lmgtfy.py index 17cca1d..ef993a3 100644 --- a/tests/modules/test_lmgtfy.py +++ b/tests/modules/test_lmgtfy.py @@ -14,3 +14,8 @@ def googbot(fakebot): def test_lmgtfy_basic(googbot): googbot.feed_line(".lmgtfy foobar asdf") googbot.act_PRIVMSG.assert_called_once_with('#test', 'chatter: http://lmgtfy.com/?q=foobar+asdf') + + +def test_lmgtfy_highlight(googbot): + googbot.feed_line("{}: lmgtfy foobar asdf".format(googbot.get_nick())) + googbot.act_PRIVMSG.assert_called_once_with('#test', 'chatter: http://lmgtfy.com/?q=foobar+asdf')