Support highlights as command triggers too

This commit is contained in:
dave 2018-02-10 16:44:51 -08:00
parent c3e14a8d0d
commit f7990667eb
8 changed files with 51 additions and 30 deletions

View File

@ -74,26 +74,36 @@ class TouchReload(Thread):
sleep(self.sleep) sleep(self.sleep)
def messageHasCommand(command, message, requireArgs=False): def messageHasCommand(command, message, requireArgs=False, withHighlight=False):
"""Check if a message has a command with or without args in it """
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. :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 :type command: str or list
:param message: the message string to look in, like "!ban Lil_Mac" :param message: the message string to look in, like "!ban Lil_Mac"
:type message: str :type message: str
:param requireArgs: if true, only validate if the command use has any amount of trailing text :param requireArgs: only match if trailing data is passed with the command used. False-like values disable This
:type requireArgs: bool""" 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: if not type(command) == list:
command = [command] command = [command]
for item in command: for item in command:
cmd = messageHasCommandSingle(item, message, requireArgs) cmd = messageHasCommandSingle(item, message, requireArgs, withHighlight)
if cmd: if cmd:
return cmd return cmd
return False 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 # Check if the message at least starts with the command
messageBeginning = message[0:len(command)] messageBeginning = message[0:len(command)]
if messageBeginning != command: if messageBeginning != command:
@ -108,13 +118,16 @@ def messageHasCommandSingle(command, message, requireArgs=False):
args = "" args = ""
if argsStart > 0: if argsStart > 0:
args = message[argsStart + 1:].strip() args = message[argsStart + 1:].strip()
args_list = args.split()
if requireArgs and args == '': if requireArgs:
return False if args == '':
return False
elif type(requireArgs) is int and len(args_list) != requireArgs:
return False
# Verified! Return the set. # Verified! Return the set.
return ParsedCommand(command, return ParsedCommand(command,
args.split(" ") if args else [], args_list,
args, args,
message) message)

View File

@ -58,6 +58,8 @@ class IRCCore(object):
self.bind_addr = None self.bind_addr = None
"""Optionally bind to a specific address. This should be a (host, port) tuple.""" """Optionally bind to a specific address. This should be a (host, port) tuple."""
self.nick = None
# Set up hooks for modules # Set up hooks for modules
self.initHooks() self.initHooks()

View File

@ -197,10 +197,13 @@ class command(hook):
:param keywords: commands to listen for :param keywords: commands to listen for
:type keywords: str :type keywords: str
:param require_args: only match if trailing data is passed with the command used :param require_args: only match if trailing data is passed with the command used. False-like values disable This
:type require_args: bool 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 :param allow_private: enable matching in private messages
:type allow_private: bool :type allow_private: bool
:param allow_highlight: treat 'Nick[:,] command args' the same as '.command args'
""" """
prefix = "." prefix = "."
@ -208,12 +211,12 @@ class command(hook):
Hotkey that must appear before commands 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") super().__init__("PRIVMSG")
self.keywords = keywords self.keywords = keywords
self.require_args = require_args self.require_args = require_args
self.allow_private = allow_private self.allow_private = allow_private
self.parsed_cmd = None self.allow_highlight = allow_highlight
def validate(self, msg, bot): def validate(self, msg, bot):
""" """
@ -224,19 +227,23 @@ class command(hook):
:param bot: reference to main pyircbot :param bot: reference to main pyircbot
:type bot: pyircbot.pyircbot.PyIRCBot :type bot: pyircbot.pyircbot.PyIRCBot
""" """
bot_nick = bot.get_nick()
if not super().validate(msg, bot): if not super().validate(msg, bot):
return False return False
if msg.args[0][0] != "#" and not self.allow_private: if msg.args[0][0] != "#" and not self.allow_private:
return False return False
for keyword in self.keywords: for keyword in self.keywords:
single = self._validate_one(msg, keyword) single = self._validate_prefixedcommand(msg, keyword, bot_nick)
if single: if single:
print(single)
return single return single
return False return False
def _validate_one(self, msg, keyword): def _validate_prefixedcommand(self, msg, keyword, nick):
with_prefix = "{}{}".format(self.prefix, keyword) 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): class regex(hook):

View File

@ -9,7 +9,6 @@
from pyircbot.modulebase import ModuleBase, command from pyircbot.modulebase import ModuleBase, command
from pyircbot.modules.ModInfo import info from pyircbot.modules.ModInfo import info
from pyircbot.common import messageHasCommand
from decimal import Decimal from decimal import Decimal
import time import time
import hashlib import hashlib

View File

@ -18,16 +18,8 @@ class LMGTFY(ModuleBase):
@info("lmgtfy <term> display a condescending internet query", cmds=["lmgtfy"]) @info("lmgtfy <term> display a condescending internet query", cmds=["lmgtfy"])
@command("lmgtfy", require_args=True) @command("lmgtfy", require_args=True)
def handleMessage(self, msg, cmd): def handleMessage(self, msg, cmd):
message = msg.trailing.split(" ")[1:] link = self.createLink(cmd.args_str)
link = self.createLink(message) self.bot.act_PRIVMSG(msg.args[0], "{}: {}".format(msg.prefix.nick, link))
self.bot.act_PRIVMSG(msg.args[0], "%s: %s" % (msg.prefix.nick, link))
def createLink(self, message): def createLink(self, message):
finalUrl = BASE_URL return BASE_URL + "+".join([urllib.parse.quote(word) for word in message.split()])
for word in message:
finalUrl += urllib.parse.quote(word)
if word != message[-1]:
finalUrl += "+"
return finalUrl

View File

@ -3,4 +3,4 @@
export PYTHONUNBUFFERED=1 export PYTHONUNBUFFERED=1
export PYTHONPATH=. export PYTHONPATH=.
py.test --fulltrace --cov=pyircbot --cov-report html -n 4 tests/ py.test --fulltrace --cov=pyircbot --cov-report html -n 4 tests/ $@

View File

@ -50,6 +50,9 @@ class FakeBaseBot(PrimitiveBot):
super().unloadmodule(module_name) super().unloadmodule(module_name)
self._modules.remove(module_name) self._modules.remove(module_name)
def get_nick(self):
return "testbot"
@pytest.fixture @pytest.fixture
def fakebot(tmpdir): def fakebot(tmpdir):

View File

@ -14,3 +14,8 @@ def googbot(fakebot):
def test_lmgtfy_basic(googbot): def test_lmgtfy_basic(googbot):
googbot.feed_line(".lmgtfy foobar asdf") googbot.feed_line(".lmgtfy foobar asdf")
googbot.act_PRIVMSG.assert_called_once_with('#test', 'chatter: http://lmgtfy.com/?q=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')