diff --git a/earwigbot/commands/__init__.py b/earwigbot/commands/__init__.py index f50094e..4b4049f 100644 --- a/earwigbot/commands/__init__.py +++ b/earwigbot/commands/__init__.py @@ -57,6 +57,16 @@ class BaseCommand(object): self.config = bot.config self.logger = bot.commands.logger.getChild(self.name) + # Convenience functions: + self.say = lambda target, msg: self.bot.frontend.say(target, msg) + self.reply = lambda data, msg: self.bot.frontend.reply(data, msg) + self.action = lambda target, msg: self.bot.frontend.action(target, msg) + self.notice = lambda target, msg: self.bot.frontend.notice(target, msg) + self.join = lambda chan: self.bot.frontend.join(chan) + self.part = lambda chan: self.bot.frontend.part(chan) + 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: @@ -66,8 +76,7 @@ class BaseCommand(object): self.logger.exception(e.format(self.name, data)) def _wrap_process(self, data): - """Make a connection alias, process() the message, and catch errors.""" - self.connection = self.bot.frontend + """process() the message, catching and reporting any errors.""" try: self.process(data) except Exception: diff --git a/earwigbot/commands/afc_report.py b/earwigbot/commands/afc_report.py index 9803a33..aa1b332 100644 --- a/earwigbot/commands/afc_report.py +++ b/earwigbot/commands/afc_report.py @@ -43,7 +43,7 @@ class Command(BaseCommand): if not data.args: msg = "what submission do you want me to give information about?" - self.connection.reply(data, msg) + self.reply(data, msg) return title = " ".join(data.args) @@ -67,8 +67,7 @@ class Command(BaseCommand): if page: return self.report(page) - msg = "submission \x0302{0}\x0301 not found.".format(title) - self.connection.reply(data, msg) + self.reply(data, "submission \x0302{0}\x0301 not found.".format(title)) def get_page(self, title): page = self.site.get_page(title, follow_redirects=False) @@ -89,9 +88,9 @@ class Command(BaseCommand): if status == "accepted": msg3 = "Reviewed by \x0302{0}\x0301 ({1})" - self.connection.reply(self.data, msg1.format(short, url)) - self.connection.say(self.data.chan, msg2.format(status)) - self.connection.say(self.data.chan, msg3.format(user_name, user_url)) + self.reply(self.data, msg1.format(short, url)) + self.say(self.data.chan, msg2.format(status)) + self.say(self.data.chan, msg3.format(user_name, user_url)) def get_status(self, page): if page.is_redirect(): diff --git a/earwigbot/commands/afc_status.py b/earwigbot/commands/afc_status.py index 08333a9..49d2a78 100644 --- a/earwigbot/commands/afc_status.py +++ b/earwigbot/commands/afc_status.py @@ -49,7 +49,7 @@ class Command(BaseCommand): if data.line[1] == "JOIN": status = " ".join(("\x02Current status:\x0F", self.get_status())) - self.connection.notice(data.nick, status) + self.notice(data.nick, status) return if data.args: @@ -57,17 +57,17 @@ class Command(BaseCommand): if action.startswith("sub") or action == "s": subs = self.count_submissions() msg = "there are \x0305{0}\x0301 pending AfC submissions (\x0302WP:AFC\x0301)." - self.connection.reply(data, msg.format(subs)) + self.reply(data, msg.format(subs)) elif action.startswith("redir") or action == "r": redirs = self.count_redirects() msg = "there are \x0305{0}\x0301 open redirect requests (\x0302WP:AFC/R\x0301)." - self.connection.reply(data, msg.format(redirs)) + self.reply(data, msg.format(redirs)) elif action.startswith("file") or action == "f": files = self.count_redirects() msg = "there are \x0305{0}\x0301 open file upload requests (\x0302WP:FFU\x0301)." - self.connection.reply(data, msg.format(files)) + self.reply(data, msg.format(files)) elif action.startswith("agg") or action == "a": try: @@ -78,21 +78,21 @@ class Command(BaseCommand): agg_num = self.get_aggregate_number(agg_data) except ValueError: msg = "\x0303{0}\x0301 isn't a number!" - self.connection.reply(data, msg.format(data.args[1])) + self.reply(data, msg.format(data.args[1])) return aggregate = self.get_aggregate(agg_num) msg = "aggregate is \x0305{0}\x0301 (AfC {1})." - self.connection.reply(data, msg.format(agg_num, aggregate)) + self.reply(data, msg.format(agg_num, aggregate)) elif action.startswith("nocolor") or action == "n": - self.connection.reply(data, self.get_status(color=False)) + self.reply(data, self.get_status(color=False)) else: msg = "unknown argument: \x0303{0}\x0301. Valid args are 'subs', 'redirs', 'files', 'agg', 'nocolor'." - self.connection.reply(data, msg.format(data.args[0])) + self.reply(data, msg.format(data.args[0])) else: - self.connection.reply(data, self.get_status()) + self.reply(data, self.get_status()) def get_status(self, color=True): subs = self.count_submissions() diff --git a/earwigbot/commands/calc.py b/earwigbot/commands/calc.py index f6d3177..1f7f834 100644 --- a/earwigbot/commands/calc.py +++ b/earwigbot/commands/calc.py @@ -32,7 +32,7 @@ class Command(BaseCommand): def process(self, data): if not data.args: - self.connection.reply(data, "what do you want me to calculate?") + self.reply(data, "what do you want me to calculate?") return query = ' '.join(data.args) @@ -47,7 +47,7 @@ class Command(BaseCommand): match = r_result.search(result) if not match: - self.connection.reply(data, "Calculation error.") + self.reply(data, "Calculation error.") return result = match.group(1) @@ -62,7 +62,7 @@ class Command(BaseCommand): result += " " + query.split(" in ", 1)[1] res = "%s = %s" % (query, result) - self.connection.reply(data, res) + self.reply(data, res) def cleanup(self, query): fixes = [ diff --git a/earwigbot/commands/chanops.py b/earwigbot/commands/chanops.py index 1bec2d6..f429a95 100644 --- a/earwigbot/commands/chanops.py +++ b/earwigbot/commands/chanops.py @@ -23,32 +23,45 @@ from earwigbot.commands import BaseCommand class Command(BaseCommand): - """Voice, devoice, op, or deop users in the channel.""" + """Voice, devoice, op, or deop users in the channel, or join or part from + other channels.""" name = "chanops" def check(self, data): - commands = ["chanops", "voice", "devoice", "op", "deop"] + commands = ["chanops", "voice", "devoice", "op", "deop", "join", "part"] if data.is_command and data.command in commands: return True return False def process(self, data): if data.command == "chanops": - msg = "available commands are !voice, !devoice, !op, and !deop." - self.connection.reply(data, msg) + msg = "available commands are !voice, !devoice, !op, !deop, !join, and !part." + self.reply(data, msg) return - if data.host not in self.config.irc["permissions"]["admins"]: - msg = "you must be a bot admin to use this command." - self.connection.reply(data, msg) + self.reply(data, "you must be a bot admin to use this command.") return - # If it is just !op/!devoice/whatever without arguments, assume they - # want to do this to themselves: - if not data.args: - target = data.nick - else: - target = data.args[0] + if data.command in ["voice", "devoice", "op", "deop"]: + # If it is just !op/!devoice/whatever without arguments, assume they + # want to do this to themselves: + if not data.args: + target = data.nick + else: + target = data.args[0] - msg = " ".join((data.command, data.chan, target)) - self.connection.say("ChanServ", msg) + msg = " ".join((data.command, data.chan, target)) + self.say("ChanServ", msg) + + else: + if not data.args: + msg = "you must specify a channel to join or part from." + self.reply(data, msg) + return + channel = data.args[0] + if not channel.startswith("#"): + channel = "#" + channel + if data.command == "join": + self.join(channel) + else: + self.part(channel) diff --git a/earwigbot/commands/crypt.py b/earwigbot/commands/crypt.py index e71e139..cf7c369 100644 --- a/earwigbot/commands/crypt.py +++ b/earwigbot/commands/crypt.py @@ -39,12 +39,12 @@ class Command(BaseCommand): def process(self, data): if data.command == "crypt": msg = "available commands are !hash, !encrypt, and !decrypt." - self.connection.reply(data, msg) + self.reply(data, msg) return if not data.args: msg = "what do you want me to {0}?".format(data.command) - self.connection.reply(data, msg) + self.reply(data, msg) return if data.command == "hash": @@ -52,14 +52,14 @@ class Command(BaseCommand): if algo == "list": algos = ', '.join(hashlib.algorithms) msg = algos.join(("supported algorithms: ", ".")) - self.connection.reply(data, msg) + self.reply(data, msg) elif algo in hashlib.algorithms: string = ' '.join(data.args[1:]) result = getattr(hashlib, algo)(string).hexdigest() - self.connection.reply(data, result) + self.reply(data, result) else: msg = "unknown algorithm: '{0}'.".format(algo) - self.connection.reply(data, msg) + self.reply(data, msg) else: key = data.args[0] @@ -67,14 +67,14 @@ class Command(BaseCommand): if not text: msg = "a key was provided, but text to {0} was not." - self.connection.reply(data, msg.format(data.command)) + self.reply(data, msg.format(data.command)) return try: if data.command == "encrypt": - self.connection.reply(data, blowfish.encrypt(key, text)) + self.reply(data, blowfish.encrypt(key, text)) else: - self.connection.reply(data, blowfish.decrypt(key, text)) + self.reply(data, blowfish.decrypt(key, text)) except blowfish.BlowfishError as error: msg = "{0}: {1}.".format(error.__class__.__name__, error) - self.connection.reply(data, msg) + self.reply(data, msg) diff --git a/earwigbot/commands/ctcp.py b/earwigbot/commands/ctcp.py index 824cb4f..45455b7 100644 --- a/earwigbot/commands/ctcp.py +++ b/earwigbot/commands/ctcp.py @@ -52,17 +52,17 @@ class Command(BaseCommand): if command == "PING": msg = " ".join(data.line[4:]) if msg: - self.connection.notice(target, "\x01PING {0}\x01".format(msg)) + self.notice(target, "\x01PING {0}\x01".format(msg)) else: - self.connection.notice(target, "\x01PING\x01") + self.notice(target, "\x01PING\x01") elif command == "TIME": ts = time.strftime("%a, %d %b %Y %H:%M:%S %Z", time.localtime()) - self.connection.notice(target, "\x01TIME {0}\x01".format(ts)) + self.notice(target, "\x01TIME {0}\x01".format(ts)) elif command == "VERSION": default = "EarwigBot - $1 - Python/$2 https://github.com/earwig/earwigbot" vers = self.config.irc.get("version", default) vers = vers.replace("$1", __version__) vers = vers.replace("$2", platform.python_version()) - self.connection.notice(target, "\x01VERSION {0}\x01".format(vers)) + self.notice(target, "\x01VERSION {0}\x01".format(vers)) diff --git a/earwigbot/commands/editcount.py b/earwigbot/commands/editcount.py index 92341b0..b503d8a 100644 --- a/earwigbot/commands/editcount.py +++ b/earwigbot/commands/editcount.py @@ -49,10 +49,10 @@ class Command(BaseCommand): count = user.editcount() except wiki.UserNotFoundError: msg = "the user \x0302{0}\x0301 does not exist." - self.connection.reply(data, msg.format(name)) + self.reply(data, msg.format(name)) return safe = quote_plus(user.name()) url = "http://toolserver.org/~tparis/pcount/index.php?name={0}&lang=en&wiki=wikipedia" msg = "\x0302{0}\x0301 has {1} edits ({2})." - self.connection.reply(data, msg.format(name, count, url.format(safe))) + self.reply(data, msg.format(name, count, url.format(safe))) diff --git a/earwigbot/commands/git.py b/earwigbot/commands/git.py index c86ff70..c22d719 100644 --- a/earwigbot/commands/git.py +++ b/earwigbot/commands/git.py @@ -35,7 +35,7 @@ class Command(BaseCommand): self.data = data if data.host not in self.config.irc["permissions"]["owners"]: msg = "you must be a bot owner to use this command." - self.connection.reply(data, msg) + self.reply(data, msg) return if not data.args: @@ -65,7 +65,7 @@ class Command(BaseCommand): else: # They asked us to do something we don't know msg = "unknown argument: \x0303{0}\x0301.".format(data.args[0]) - self.connection.reply(data, msg) + self.reply(data, msg) def exec_shell(self, command): """Execute a shell command and get the output.""" @@ -89,13 +89,13 @@ class Command(BaseCommand): for key in sorted(help.keys()): msg += "\x0303{0}\x0301 ({1}), ".format(key, help[key]) msg = msg[:-2] # Trim last comma and space - self.connection.reply(self.data, "sub-commands are: {0}.".format(msg)) + self.reply(self.data, "sub-commands are: {0}.".format(msg)) def do_branch(self): """Get our current branch.""" branch = self.exec_shell("git name-rev --name-only HEAD") msg = "currently on branch \x0302{0}\x0301.".format(branch) - self.connection.reply(self.data, msg) + self.reply(self.data, msg) def do_branches(self): """Get a list of branches.""" @@ -106,14 +106,14 @@ class Command(BaseCommand): branches = branches.replace('\n ', ', ') branches = branches.strip() msg = "branches: \x0302{0}\x0301.".format(branches) - self.connection.reply(self.data, msg) + self.reply(self.data, msg) def do_checkout(self): """Switch branches.""" try: branch = self.data.args[1] except IndexError: # no branch name provided - self.connection.reply(self.data, "switch to which branch?") + self.reply(self.data, "switch to which branch?") return current_branch = self.exec_shell("git name-rev --name-only HEAD") @@ -122,51 +122,51 @@ class Command(BaseCommand): result = self.exec_shell("git checkout %s" % branch) if "Already on" in result: msg = "already on \x0302{0}\x0301!".format(branch) - self.connection.reply(self.data, msg) + self.reply(self.data, msg) else: ms = "switched from branch \x0302{1}\x0301 to \x0302{1}\x0301." msg = ms.format(current_branch, branch) - self.connection.reply(self.data, msg) + self.reply(self.data, msg) except subprocess.CalledProcessError: # Git couldn't switch branches; assume the branch doesn't exist: msg = "branch \x0302{0}\x0301 doesn't exist!".format(branch) - self.connection.reply(self.data, msg) + self.reply(self.data, msg) def do_delete(self): """Delete a branch, while making sure that we are not already on it.""" try: delete_branch = self.data.args[1] except IndexError: # no branch name provided - self.connection.reply(self.data, "delete which branch?") + self.reply(self.data, "delete which branch?") return current_branch = self.exec_shell("git name-rev --name-only HEAD") if current_branch == delete_branch: msg = "you're currently on this branch; please checkout to a different branch before deleting." - self.connection.reply(self.data, msg) + self.reply(self.data, msg) return try: self.exec_shell("git branch -d %s" % delete_branch) msg = "branch \x0302{0}\x0301 has been deleted locally." - self.connection.reply(self.data, msg.format(delete_branch)) + self.reply(self.data, msg.format(delete_branch)) except subprocess.CalledProcessError: # Git couldn't switch branches; assume the branch doesn't exist: msg = "branch \x0302{0}\x0301 doesn't exist!".format(delete_branch) - self.connection.reply(self.data, msg) + self.reply(self.data, msg) def do_pull(self): """Pull from our remote repository.""" branch = self.exec_shell("git name-rev --name-only HEAD") msg = "pulling from remote (currently on \x0302{0}\x0301)..." - self.connection.reply(self.data, msg.format(branch)) + self.reply(self.data, msg.format(branch)) result = self.exec_shell("git pull") if "Already up-to-date." in result: - self.connection.reply(self.data, "done; no new changes.") + self.reply(self.data, "done; no new changes.") else: regex = "\s*((.*?)\sfile(.*?)tions?\(-\))" changes = re.findall(regex, result)[0][0] @@ -176,11 +176,11 @@ class Command(BaseCommand): cmnd_url = "git config --get remote.{0}.url".format(remote) url = self.exec_shell(cmnd_url) msg = "done; {0} [from {1}].".format(changes, url) - self.connection.reply(self.data, msg) + self.reply(self.data, msg) except subprocess.CalledProcessError: # Something in .git/config is not specified correctly, so we # cannot get the remote's URL. However, pull was a success: - self.connection.reply(self.data, "done; %s." % changes) + self.reply(self.data, "done; %s." % changes) def do_status(self): """Check whether we have anything to pull.""" @@ -188,7 +188,7 @@ class Command(BaseCommand): result = self.exec_shell("git fetch --dry-run") if not result: # Nothing was fetched, so remote and local are equal msg = "last commit was {0}. Local copy is \x02up-to-date\x0F with remote." - self.connection.reply(self.data, msg.format(last)) + self.reply(self.data, msg.format(last)) else: msg = "last local commit was {0}. Remote is \x02ahead\x0F of local copy." - self.connection.reply(self.data, msg.format(last)) + self.reply(self.data, msg.format(last)) diff --git a/earwigbot/commands/help.py b/earwigbot/commands/help.py index 95d9e39..6897484 100644 --- a/earwigbot/commands/help.py +++ b/earwigbot/commands/help.py @@ -40,7 +40,7 @@ class Command(BaseCommand): msg = "Hi, I'm a bot! I have {0} commands loaded: {1}. You can get help for any command with '!help '." cmnds = sorted(self.bot.commands) msg = msg.format(len(cmnds), ', '.join(cmnds)) - self.connection.reply(data, msg) + self.reply(data, msg) def do_command_help(self, data): """Give the user help for a specific command.""" @@ -60,9 +60,9 @@ class Command(BaseCommand): doc = cmnd.__doc__.replace("\n", "") doc = re.sub("\s\s+", " ", doc) msg = "help for command \x0303{0}\x0301: \"{1}\"" - self.connection.reply(data, msg.format(command, doc)) + self.reply(data, msg.format(command, doc)) return break msg = "sorry, no help for \x0303{0}\x0301.".format(command) - self.connection.reply(data, msg) + self.reply(data, msg) diff --git a/earwigbot/commands/link.py b/earwigbot/commands/link.py index 675096e..6f84d44 100644 --- a/earwigbot/commands/link.py +++ b/earwigbot/commands/link.py @@ -43,15 +43,15 @@ class Command(BaseCommand): if re.search("(\[\[(.*?)\]\])|(\{\{(.*?)\}\})", msg): links = self.parse_line(msg) links = " , ".join(links) - self.connection.reply(data, links) + self.reply(data, links) elif data.command == "link": if not data.args: - self.connection.reply(data, "what do you want me to link to?") + self.reply(data, "what do you want me to link to?") return pagename = ' '.join(data.args) link = self.parse_link(pagename) - self.connection.reply(data, link) + self.reply(data, link) def parse_line(self, line): results = [] diff --git a/earwigbot/commands/praise.py b/earwigbot/commands/praise.py index c9e3950..fb611f5 100644 --- a/earwigbot/commands/praise.py +++ b/earwigbot/commands/praise.py @@ -45,7 +45,7 @@ class Command(BaseCommand): msg = "You use this command to praise certain people. Who they are is a secret." else: msg = "You're doing it wrong." - self.connection.reply(data, msg) + self.reply(data, msg) return - self.connection.say(data.chan, msg) + self.say(data.chan, msg) diff --git a/earwigbot/commands/quit.py b/earwigbot/commands/quit.py index 9b8cbc3..db3f168 100644 --- a/earwigbot/commands/quit.py +++ b/earwigbot/commands/quit.py @@ -33,8 +33,7 @@ class Command(BaseCommand): def process(self, data): if data.host not in self.config.irc["permissions"]["owners"]: - msg = "you must be a bot owner to use this command." - self.connection.reply(data, msg) + self.reply(data, "you must be a bot owner to use this command.") return if data.command == "quit": self.do_quit(data) @@ -46,7 +45,7 @@ class Command(BaseCommand): def do_quit(self, data): nick = self.config.irc.frontend["nick"] if not data.args or data.args[0].lower() != nick.lower(): - self.connection.reply(data, "to confirm this action, the first argument must be my nickname.") + self.reply(data, "to confirm this action, the first argument must be my nickname.") return if data.args[1:]: msg = " ".join(data.args[1:]) @@ -66,4 +65,4 @@ class Command(BaseCommand): self.logger.info("Reloading IRC commands and bot tasks") self.bot.commands.load() self.bot.tasks.load() - self.connection.reply(data, "IRC commands and bot tasks reloaded.") + self.reply(data, "IRC commands and bot tasks reloaded.") diff --git a/earwigbot/commands/registration.py b/earwigbot/commands/registration.py index 6db8775..ad42269 100644 --- a/earwigbot/commands/registration.py +++ b/earwigbot/commands/registration.py @@ -30,7 +30,7 @@ class Command(BaseCommand): name = "registration" def check(self, data): - commands = ["registration", "age"] + commands = ["registration", "reg", "age"] if data.is_command and data.command in commands: return True return False @@ -49,7 +49,7 @@ class Command(BaseCommand): reg = user.registration() except wiki.UserNotFoundError: msg = "the user \x0302{0}\x0301 does not exist." - self.connection.reply(data, msg.format(name)) + self.reply(data, msg.format(name)) return date = time.strftime("%b %d, %Y at %H:%M:%S UTC", reg) @@ -64,7 +64,7 @@ class Command(BaseCommand): gender = "They're" msg = "\x0302{0}\x0301 registered on {1}. {2} {3} old." - self.connection.reply(data, msg.format(name, date, gender, age)) + self.reply(data, msg.format(name, date, gender, age)) def get_diff(self, t1, t2): parts = {"years": 31536000, "days": 86400, "hours": 3600, diff --git a/earwigbot/commands/remind.py b/earwigbot/commands/remind.py index 115cb4c..930deda 100644 --- a/earwigbot/commands/remind.py +++ b/earwigbot/commands/remind.py @@ -37,19 +37,19 @@ class Command(BaseCommand): def process(self, data): if not data.args: msg = "please specify a time (in seconds) and a message in the following format: !remind