diff --git a/earwigbot/commands/__init__.py b/earwigbot/commands/__init__.py index 1dd745d..8e08011 100644 --- a/earwigbot/commands/__init__.py +++ b/earwigbot/commands/__init__.py @@ -67,22 +67,6 @@ class BaseCommand(object): self.mode = lambda t, level, msg: self.bot.frontend.mode(t, level, msg) self.pong = lambda target: self.bot.frontend.pong(target) - def _wrap_check(self, data): - """Check whether this command should be called, catching errors.""" - try: - return self.check(data) - except Exception: - e = "Error checking command '{0}' with data: {1}:" - self.logger.exception(e.format(self.name, data)) - - def _wrap_process(self, data): - """process() the message, catching and reporting any errors.""" - try: - self.process(data) - except Exception: - e = "Error executing command '{0}':" - self.logger.exception(e.format(data.command)) - def check(self, data): """Return whether this command should be called in response to 'data'. diff --git a/earwigbot/commands/help.py b/earwigbot/commands/help.py index 6897484..e1e6374 100644 --- a/earwigbot/commands/help.py +++ b/earwigbot/commands/help.py @@ -29,11 +29,21 @@ class Command(BaseCommand): """Displays help information.""" name = "help" + def check(self, data): + if data.is_command: + if data.command == "help": + return True + if not data.command and data.trigger == data.my_nick: + return True + return False + def process(self, data): - if not data.args: - self.do_main_help(data) - else: + if not data.command: + self.do_hello(data) + if data.args: self.do_command_help(data) + else: + self.do_main_help(data) def do_main_help(self, data): """Give the user a general help message with a list of all commands.""" @@ -66,3 +76,6 @@ class Command(BaseCommand): msg = "sorry, no help for \x0303{0}\x0301.".format(command) self.reply(data, msg) + + def do_hello(self, data): + self.say(data.chan, "Yes, {0}?".format(data.nick)) diff --git a/earwigbot/commands/quit.py b/earwigbot/commands/quit.py index 9ca1f38..e07d060 100644 --- a/earwigbot/commands/quit.py +++ b/earwigbot/commands/quit.py @@ -43,12 +43,13 @@ class Command(BaseCommand): self.do_reload(data) def do_quit(self, data): - nick = self.config.irc.frontend["nick"] - if not data.args or data.args[0].lower() != nick.lower(): + args = data.args + nick = self.config.irc.frontend["nick"].lower() + if data.trigger != nick and (not args or args[0].lower() != nick): self.reply(data, "to confirm this action, the first argument must be my nickname.") return - if data.args[1:]: - msg = " ".join(data.args[1:]) + if args[1:]: + msg = " ".join(args[1:]) self.bot.stop("Stopped by {0}: {1}".format(data.nick, msg)) else: self.bot.stop("Stopped by {0}".format(data.nick)) diff --git a/earwigbot/commands/threads.py b/earwigbot/commands/threads.py index 39f2517..f9a6219 100644 --- a/earwigbot/commands/threads.py +++ b/earwigbot/commands/threads.py @@ -119,7 +119,7 @@ class Command(BaseCommand): tasks = ", ".join(tasklist) - msg = "{0} tasks loaded: {1}.".format(len(tasklist), tasks) + msg = "\x02{0}\x0F tasks loaded: {1}.".format(len(tasklist), tasks) self.reply(self.data, msg) def do_start(self): diff --git a/earwigbot/irc/data.py b/earwigbot/irc/data.py index fae6a52..b83bcf6 100644 --- a/earwigbot/irc/data.py +++ b/earwigbot/irc/data.py @@ -33,8 +33,9 @@ class KwargParseException(Exception): class Data(object): """Store data from an individual line received on IRC.""" - def __init__(self, line): + def __init__(self, bot, line): self.line = line + self.my_nick = bot.config.irc["frontend"]["nick"].lower() self.chan = self.nick = self.ident = self.host = self.msg = "" def parse_args(self): @@ -46,20 +47,28 @@ class Data(object): # Isolate command arguments: self.args = args[1:] - self.is_command = False # is this message a command? + self.is_command = False # Is this message a command? + self.trigger = None # What triggered this command? (!, ., or our nick) try: - self.command = args[0] + self.command = args[0].lower() except IndexError: self.command = None + return - try: - if self.command.startswith('!') or self.command.startswith('.'): - self.is_command = True - self.command = self.command[1:] # Strip the '!' or '.' - self.command = self.command.lower() - except AttributeError: - pass + if self.command.startswith("!") or self.command.startswith("."): + # e.g. "!command arg1 arg2" + self.is_command = True + self.trigger = self.command[0] + self.command = self.command[1:] # Strip the "!" or "." + elif self.command.startswith(self.my_nick): + # e.g. "EarwigBot, command arg1 arg2" + self.is_command = True + self.trigger = self.my_nick + try: + self.command = self.args.pop(0).lower() + except IndexError: + self.command = "" def parse_kwargs(self): """Parse keyword arguments embedded in self.args. diff --git a/earwigbot/irc/frontend.py b/earwigbot/irc/frontend.py index 2065ff1..35accd8 100644 --- a/earwigbot/irc/frontend.py +++ b/earwigbot/irc/frontend.py @@ -51,7 +51,7 @@ class Frontend(IRCConnection): def _process_message(self, line): """Process a single message from IRC.""" line = line.strip().split() - data = Data(line) # New Data instance to store info about this line + data = Data(self.bot, line) if line[1] == "JOIN": data.nick, data.ident, data.host = self.sender_regex.findall(line[0])[0] diff --git a/earwigbot/managers.py b/earwigbot/managers.py index 6c2531b..74f4ea5 100644 --- a/earwigbot/managers.py +++ b/earwigbot/managers.py @@ -147,13 +147,29 @@ class CommandManager(_ResourceManager): base = super(CommandManager, self) base.__init__(bot, "commands", "Command", BaseCommand) + def _wrap_check(self, command, data): + """Check whether a command should be called, catching errors.""" + try: + return command.check(data) + except Exception: + e = "Error checking command '{0}' with data: {1}:" + self.logger.exception(e.format(command.name, data)) + + def _wrap_process(self, command, data): + """process() the message, catching and reporting any errors.""" + try: + command.process(data) + except Exception: + e = "Error executing command '{0}':" + self.logger.exception(e.format(data.command)) + def check(self, hook, data): """Given an IRC event, check if there's anything we can respond to.""" self.lock.acquire() for command in self._resources.itervalues(): - if hook in command.hooks and command._wrap_check(data): + if hook in command.hooks and self._wrap_check(command, data): self.lock.release() - command._wrap_process(data) + self._wrap_process(command, data) return self.lock.release() diff --git a/earwigbot/tasks/afc_statistics.py b/earwigbot/tasks/afc_statistics.py index 51568a9..b177734 100644 --- a/earwigbot/tasks/afc_statistics.py +++ b/earwigbot/tasks/afc_statistics.py @@ -165,11 +165,9 @@ class Task(BaseTask): table, where keys are column names and values are their cell contents. """ row = "{0}|s={page_status}|t={page_title}|h={page_short}|z={page_size}|" - row += "sr={page_special_user}|sh={page_special_hidden}|sd={page_special_time}|si={page_special_oldid}|" - row += "mr={page_modify_user}|mh={page_modify_hidden}|md={page_modify_time}|mi={page_modify_oldid}" + row += "sr={page_special_user}|sd={page_special_time}|si={page_special_oldid}|" + row += "mr={page_modify_user}|md={page_modify_time}|mi={page_modify_oldid}" - page["page_special_hidden"] = self.format_hidden(page["page_special_time"]) - page["page_modify_hidden"] = self.format_hidden(page["page_modify_time"]) page["page_special_time"] = self.format_time(page["page_special_time"]) page["page_modify_time"] = self.format_time(page["page_modify_time"]) @@ -182,13 +180,6 @@ class Task(BaseTask): """Format a datetime into the standard MediaWiki timestamp format.""" return dt.strftime("%H:%M, %d %b %Y") - def format_hidden(self, dt): - """Convert a datetime into seconds since the epoch. - - This is used by the template as a hidden sortkey. - """ - return int((dt - datetime(1970, 1, 1)).total_seconds()) - def sync(self, **kwargs): """Synchronize our local statistics database with the site.