|
- # Copyright (C) 2021 Ben Kurtovic <ben.kurtovic@gmail.com>
- #
- # Permission is hereby granted, free of charge, to any person obtaining a copy
- # of this software and associated documentation files (the "Software"), to deal
- # in the Software without restriction, including without limitation the rights
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- # copies of the Software, and to permit persons to whom the Software is
- # furnished to do so, subject to the following conditions:
- #
- # The above copyright notice and this permission notice shall be included in
- # all copies or substantial portions of the Software.
- #
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- # SOFTWARE.
-
- import base64
- import pickle
- import re
-
- from earwigbot.commands import Command
- from earwigbot.config.permissions import User
-
-
- class PartWhen(Command):
- """Ask the bot to part the channel when a condition is met."""
-
- name = "partwhen"
- commands = ["partwhen", "unpartwhen"]
- hooks = ["join", "msg"]
-
- def setup(self):
- self._conds = self._load_conditions()
-
- def check(self, data):
- if data.is_command and data.command in self.commands:
- return True
- try:
- if data.line[1] == "JOIN":
- if data.chan in self._conds and "join" in self._conds[data.chan]:
- return True
- except IndexError:
- pass
- return False
-
- def process(self, data):
- if data.line[1] == "JOIN":
- self._handle_join(data)
- return
-
- if not self.config.irc["permissions"].is_admin(data):
- self.reply(data, "You must be a bot admin to use this command.")
- return
-
- channel = data.chan
- args = data.args
- if args and args[0].startswith("#"):
- # "!partwhen #channel <event> <args>..."
- channel = args[0]
- args = args[1:]
-
- if data.command == "unpartwhen":
- if self._conds.get(channel):
- del self._conds[channel]
- self._save_conditions()
- self.reply(
- data,
- "Cleared part conditions for {}.".format(
- "this channel" if channel == data.chan else channel
- ),
- )
- else:
- self.reply(data, "No part conditions set.")
- return
-
- if not args:
- conds = self._conds.get(channel, {})
- existing = "; ".join(
- "{} {}".format(cond, ", ".join(str(user) for user in users))
- for cond, users in conds.iteritems()
- )
- if existing:
- status = f"Current part conditions: {existing}."
- else:
- status = "No part conditions set for {}.".format(
- "this channel" if channel == data.chan else channel
- )
- self.reply(
- data,
- f"{status} Usage: !{data.command} [<channel>] <event> <args>...",
- )
- return
-
- event = args[0]
- args = args[1:]
- if event == "join":
- if not args:
- self.reply(
- data,
- "Join event requires an argument for the user joining, "
- "in nick!ident@host syntax.",
- )
- return
- cond = args[0]
- match = re.match(r"(.*?)!(.*?)@(.*?)$", cond)
- if not match:
- self.reply(
- data,
- "User join pattern is invalid; should use "
- "nick!ident@host syntax.",
- )
- return
- conds = self._conds.setdefault(channel, {}).setdefault("join", [])
- conds.append(User(match.group(1), match.group(2), match.group(3)))
- self._save_conditions()
- self.reply(
- data,
- "Okay, I will leave {} when {} joins.".format(
- "the channel" if channel == data.chan else channel, cond
- ),
- )
- else:
- self.reply(data, f"Unknown event: {event} (valid events: join).")
-
- def _handle_join(self, data):
- user = User(data.nick, data.ident, data.host)
- conds = self._conds.get(data.chan, {}).get("join", {})
- for cond in conds:
- if user in cond:
- self.logger.info(
- f"Parting {data.chan} because {str(user)} met join condition {str(cond)}"
- )
- self.part(data.chan, f"Requested to leave when {data.nick} joined")
- break
-
- def _load_conditions(self):
- permdb = self.config.irc["permissions"]
- try:
- raw = permdb.get_attr("command:partwhen", "data")
- except KeyError:
- return {}
- return pickle.loads(base64.b64decode(raw))
-
- def _save_conditions(self):
- permdb = self.config.irc["permissions"]
- raw = base64.b64encode(pickle.dumps(self._conds, pickle.HIGHEST_PROTOCOL))
- permdb.set_attr("command:partwhen", "data", raw)
|