diff options
-rw-r--r-- | bot/cogs/bot.py | 104 |
1 files changed, 66 insertions, 38 deletions
diff --git a/bot/cogs/bot.py b/bot/cogs/bot.py index 2663b79a8..a29aff9d5 100644 --- a/bot/cogs/bot.py +++ b/bot/cogs/bot.py @@ -1,5 +1,6 @@ # coding=utf-8 import ast +import re import time from discord import Embed, Message @@ -22,11 +23,11 @@ class Bot: self.bot = bot # Stores allowed channels plus unix timestamp from last call - self.previous_format_times = {HELP1_CHANNEL: 0, - HELP2_CHANNEL: 0, - HELP3_CHANNEL: 0, - PYTHON_CHANNEL: 0, - DEVTEST_CHANNEL: 0 + self.channel_cooldowns = {HELP1_CHANNEL: 0, + HELP2_CHANNEL: 0, + HELP3_CHANNEL: 0, + PYTHON_CHANNEL: 0, + DEVTEST_CHANNEL: 0 } # noqa. E124 @group(invoke_without_command=True, name="bot", hidden=True) @@ -73,40 +74,67 @@ class Bot: await ctx.invoke(self.info) + def codeblock_stripping(self, msg: str): + """ + Strip msg in order to find Python code. + + Tries to strip out Python code out of msg and returns the stripped block or + None if the block is a valid Python codeblock. + """ + if msg.count("\n") >= 3: + # Filtering valid Python codeblocks and exiting if a valid Python codeblock is found + if re.search("```(python|py)\n((?:.*\n*)+)```", msg, re.IGNORECASE): + return None + else: + # Stripping backticks from every line of the message. + content = "" + for line in msg.splitlines(): + content += line.strip("`") + "\n" + + content = content.strip() + + # Remove "Python" or "Py" from top of the message if exists + if content.lower().startswith("python"): + content = content[6:] + elif content.lower().startswith("py"): + content = content[2:] + + # Strip again to remove the whitespace(s) left before the code + # If the msg looked like "Python <code>" before removing Python + content = content.strip() + return content + async def on_message(self, msg: Message): - if msg.channel.id in self.previous_format_times: - if time.time()-self.previous_format_times[msg.channel.id] > 300 or msg.channel.id == DEVTEST_CHANNEL: - if msg.content.count("\n") >= 3: - try: - # Some users formatted multi-line code using `'sip(" - # This fixes that by treating them as nothing. - if "`" in msg.content: - msg.content = msg.content[:-1][1:] - tree = ast.parse(msg.content) - - # Attempts to parse the message into an AST node. - # Invalid Python code will raise a SyntaxError. - if not all(isinstance(node, ast.Expr) for node in tree.body): - - # Multiple lines of single words could be interpreted as expressions. - # This check is to avoid all nodes being parsed as expressions. - # (e.g. words over multiple lines) - howto = ("Please use syntax highlighted blocks, as it makes " - "your code more legible for other users.\n" - "\nTo do this, you should input your content like this:\n" - "\n\`\`\`python\n" - "print(\"Hello world!\")\n" - "\`\`\`\n" - "\nThis will result in the following:\n" - "```python\n" - "print(\"Hello world!\")" - "```" - ) # noqa. E124 - information = Embed(title="Code formatting", description=howto) - await msg.channel.send(embed=information) - self.previous_format_times[msg.channel.id] = time.time() - except SyntaxError: - pass + if msg.channel.id in self.channel_cooldowns: + on_cooldown = time.time() - self.channel_cooldowns[msg.channel.id] < 300 + if not on_cooldown or msg.channel.id == DEVTEST_CHANNEL: + try: + content = self.codeblock_stripping(msg.content) + if not content: + return + + # Attempts to parse the message into an AST node. + # Invalid Python code will raise a SyntaxError. + tree = ast.parse(content) + + # Multiple lines of single words could be interpreted as expressions. + # This check is to avoid all nodes being parsed as expressions. + # (e.g. words over multiple lines) + if not all(isinstance(node, ast.Expr) for node in tree.body): + codeblock_tag = await self.bot.get_cog("Tags").get_tag_data("codeblock") + if codeblock_tag == {}: + # todo: add logging + return + howto = (f"Hey {msg.author.mention}!\n\n" + "I noticed you were trying to paste code into this channel.\n\n" + f"{codeblock_tag['tag_content']}") + + howto_embed = Embed(description=howto) + await msg.channel.send(embed=howto_embed) + self.channel_cooldowns[msg.channel.id] = time.time() + except SyntaxError: + # todo: add logging + pass def setup(bot): |