internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: python-discord/bot

Issue:
Nickname Filter Also Catches Webhooks
The nickname filtering introduced by #964 also matches on webhooks, causing false positives. Posts from webhooks should be ignored.


Discussion:

Resolving patch:
diff --git a/bot/cogs/filtering.py b/bot/cogs/filtering.py
--- a/bot/cogs/filtering.py
+++ b/bot/cogs/filtering.py
@@ -124,7 +124,10 @@ def mod_log(self) -> ModLog:
     async def on_message(self, msg: Message) -> None:
         """Invoke message filter for new messages."""
         await self._filter_message(msg)
-        await self.check_bad_words_in_name(msg.author)
+
+        # Ignore webhook messages.
+        if msg.webhook_id is None:
+            await self.check_bad_words_in_name(msg.author)
 
     @Cog.listener()
     async def on_message_edit(self, before: Message, after: Message) -> None:


Test patch:
Repository: python-discord/bot

Issue:
Handle error for long poll titles in a user-friendly way
Sentry Issue: [BOT-7Q](https://sentry.io/organizations/python-discord/issues/1821866467/?referrer=github_integration)

The poll command puts the poll's question in the embed's title, which has a maximum character limit of 256. Instead of letting the exception for a 400 response status propagate, an error should be displayed to the user indicating the question given is too long. Automatic truncation is probably a bad idea in this context. The user should manually figure out a shorter phrasing.


Discussion:

Resolving patch:
diff --git a/bot/cogs/utils.py b/bot/cogs/utils.py
--- a/bot/cogs/utils.py
+++ b/bot/cogs/utils.py
@@ -232,6 +232,8 @@ async def vote(self, ctx: Context, title: clean_content(fix_channel_mentions=Tru
         A maximum of 20 options can be provided, as Discord supports a max of 20
         reactions on a single message.
         """
+        if len(title) > 256:
+            raise BadArgument("The title cannot be longer than 256 characters.")
         if len(options) < 2:
             raise BadArgument("Please provide at least 2 options.")
         if len(options) > 20:


Test patch:
Repository: python-discord/bot

Issue:
API lag may lead to more than 2 available help channels
`on_message` uses a lock to ensure messages sent in available channels are processed sequentially. After it acquires the lock, it checks if the channel has already been moved out of available. If it has, then it aborts further processing. The problem is that this relies on Discord moving the channel in a reasonable amount of time. If it happens slowly, then the next message that acquires the lock will still think the channel can be claimed. 

This is because only the request to move the channel is awaited. It can be sure the request has been sent, but not that Discord has processed it and moved the channel. To do that, it'd have to wait for a guild channel update event. That's just one solution. Another idea I have is to check if the channel has a claimant associated with it, since that is already tracked for other purposes.


Discussion:

Resolving patch:
diff --git a/bot/cogs/help_channels.py b/bot/cogs/help_channels.py
--- a/bot/cogs/help_channels.py
+++ b/bot/cogs/help_channels.py
@@ -694,7 +694,7 @@ async def on_message(self, message: discord.Message) -> None:
         async with self.on_message_lock:
             log.trace(f"on_message lock acquired for {message.id}.")
 
-            if not self.is_in_category(channel, constants.Categories.help_available):
+            if await self.help_channel_claimants.contains(channel.id):
                 log.debug(
                     f"Message {message.id} will not make #{channel} ({channel.id}) in-use "
                     f"because another message in the channel already triggered that."


Test patch:
Repository: python-discord/bot

Issue:
API lag may lead to more than 2 available help channels
`on_message` uses a lock to ensure messages sent in available channels are processed sequentially. After it acquires the lock, it checks if the channel has already been moved out of available. If it has, then it aborts further processing. The problem is that this relies on Discord moving the channel in a reasonable amount of time. If it happens slowly, then the next message that acquires the lock will still think the channel can be claimed. 

This is because only the request to move the channel is awaited. It can be sure the request has been sent, but not that Discord has processed it and moved the channel. To do that, it'd have to wait for a guild channel update event. That's just one solution. Another idea I have is to check if the channel has a claimant associated with it, since that is already tracked for other purposes.


Discussion:

Resolving patch:
diff --git a/bot/cogs/help_channels.py b/bot/cogs/help_channels.py
--- a/bot/cogs/help_channels.py
+++ b/bot/cogs/help_channels.py
@@ -215,9 +215,6 @@ async def close_command(self, ctx: commands.Context) -> None:
         log.trace("close command invoked; checking if the channel is in-use.")
         if ctx.channel.category == self.in_use_category:
             if await self.dormant_check(ctx):
-
-                # Remove the claimant and the cooldown role
-                await self.help_channel_claimants.delete(ctx.channel.id)
                 await self.remove_cooldown_role(ctx.author)
 
                 # Ignore missing task when cooldown has passed but the channel still isn't dormant.
@@ -551,6 +548,7 @@ async def move_to_dormant(self, channel: discord.TextChannel, caller: str) -> No
 
         A caller argument is provided for metrics.
         """
+        await self.help_channel_claimants.delete(channel.id)
         msg_id = await self.question_messages.pop(channel.id)
 
         try:


Test patch:
Repository: python-discord/bot

Issue:
Existing offensive messages sometimes posted again
Sentry Issue: [BOT-6B](https://sentry.io/organizations/python-discord/issues/1732235421/?referrer=github_integration)

My guess is this happens when an edited message re-triggers a filter. If this is indeed the case, then the error can simply be ignored.

```
ResponseCodeError: Status: 400 Response: {'id': ['offensive message with this id already exists.']}
(1 additional frame(s) were not displayed)
...
  File "bot/cogs/filtering.py", line 143, in on_message_edit
    await self._filter_message(after, delta)
  File "bot/cogs/filtering.py", line 304, in _filter_message
    await self.bot.api_client.post('bot/offensive-messages', json=data)
  File "bot/api.py", line 127, in post
    return await self.request("POST", endpoint, raise_for_status=raise_for_status, **kwargs)
  File "bot/api.py", line 114, in request
    await self.maybe_raise_for_status(resp, raise_for_status)
  File "bot/api.py", line 104, in maybe_raise_for_status
    raise ResponseCodeError(response=response, response_json=response_json)

Unhandled exception in on_message_edit.
```


Discussion:

Resolving patch:
diff --git a/bot/cogs/filtering.py b/bot/cogs/filtering.py
--- a/bot/cogs/filtering.py
+++ b/bot/cogs/filtering.py
@@ -11,6 +11,7 @@
 from discord.ext.commands import Cog
 from discord.utils import escape_markdown
 
+from bot.api import ResponseCodeError
 from bot.bot import Bot
 from bot.cogs.moderation import ModLog
 from bot.constants import (
@@ -301,9 +302,16 @@ async def _filter_message(self, msg: Message, delta: Optional[int] = None) -> No
                                 'delete_date': delete_date
                             }
 
-                            await self.bot.api_client.post('bot/offensive-messages', json=data)
-                            self.schedule_msg_delete(data)
-                            log.trace(f"Offensive message {msg.id} will be deleted on {delete_date}")
+                            try:
+                                await self.bot.api_client.post('bot/offensive-messages', json=data)
+                            except ResponseCodeError as e:
+                                if e.status == 400 and "already exists" in e.response_json.get("id", [""])[0]:
+                                    log.debug(f"Offensive message {msg.id} already exists.")
+                                else:
+                                    log.error(f"Offensive message {msg.id} failed to post: {e}")
+                            else:
+                                self.schedule_msg_delete(data)
+                                log.trace(f"Offensive message {msg.id} will be deleted on {delete_date}")
 
                         if is_private:
                             channel_str = "via DM"


Test patch:
Repository: python-discord/bot

Issue:
Reddit cog does not escape markdown in post titles
Discord markdown in reddit post titles is left unhandled and can sometimes break the links:
![redditpydisbot](https://i.imgur.com/ut0gzFQ.png)

For the basic markdown passing it through d.py's `escape_markdown` should work, but from a quick look I haven't found a way to escape brackets in post titles, which breaks the text links. A replacement with similar unicode chars is an option


Discussion:

Resolving patch:
diff --git a/bot/cogs/reddit.py b/bot/cogs/reddit.py
--- a/bot/cogs/reddit.py
+++ b/bot/cogs/reddit.py
@@ -10,6 +10,7 @@
 from discord import Colour, Embed, TextChannel
 from discord.ext.commands import Cog, Context, group
 from discord.ext.tasks import loop
+from discord.utils import escape_markdown
 
 from bot.bot import Bot
 from bot.constants import Channels, ERROR_REPLIES, Emojis, Reddit as RedditConfig, STAFF_ROLES, Webhooks
@@ -187,6 +188,8 @@ async def get_top_posts(self, subreddit: Subreddit, time: str = "all", amount: i
             author = data["author"]
 
             title = textwrap.shorten(data["title"], width=64, placeholder="...")
+            # Normal brackets interfere with Markdown.
+            title = escape_markdown(title).replace("[", "⦋").replace("]", "⦌")
             link = self.URL + data["permalink"]
 
             embed.description += (


Test patch:
Repository: python-discord/bot

Issue:
Leaked bot token still relayed to big-brother if user is watched
If a user pastes a bot token and the user is currently being watched (big-brother or nomination) then it will relay the message to the watch channel, which is not ideal. The same thing would apply for webhook URLs.
Ideally it would either send nothing, or possibly a message saying that it was removed, to the watch channels.



Discussion:
We need to check for the presence of a token in `on_message` before further processing. If I remember correctly, something similar is already being done for the invalid code block detection.
Yeah, I agree wirh Mark. The token check must be made on the bot's `on_message` listener rather than in the cog's `on_message` listener because IIRC, the bot's listener is triggered first and you can stop all the command processing there. 

Resolving patch:
diff --git a/bot/cogs/bot.py b/bot/cogs/bot.py
--- a/bot/cogs/bot.py
+++ b/bot/cogs/bot.py
@@ -9,6 +9,7 @@
 
 from bot.bot import Bot
 from bot.cogs.token_remover import TokenRemover
+from bot.cogs.webhook_remover import WEBHOOK_URL_RE
 from bot.constants import Categories, Channels, DEBUG_MODE, Guild, MODERATION_ROLES, Roles, URLs
 from bot.decorators import with_role
 from bot.utils.messages import wait_for_deletion
@@ -240,6 +241,7 @@ async def on_message(self, msg: Message) -> None:
             and not msg.author.bot
             and len(msg.content.splitlines()) > 3
             and not TokenRemover.find_token_in_message(msg)
+            and not WEBHOOK_URL_RE.search(msg.content)
         )
 
         if parse_codeblock:  # no token in the msg
diff --git a/bot/cogs/watchchannels/watchchannel.py b/bot/cogs/watchchannels/watchchannel.py
--- a/bot/cogs/watchchannels/watchchannel.py
+++ b/bot/cogs/watchchannels/watchchannel.py
@@ -15,6 +15,8 @@
 from bot.api import ResponseCodeError
 from bot.bot import Bot
 from bot.cogs.moderation import ModLog
+from bot.cogs.token_remover import TokenRemover
+from bot.cogs.webhook_remover import WEBHOOK_URL_RE
 from bot.constants import BigBrother as BigBrotherConfig, Guild as GuildConfig, Icons
 from bot.pagination import LinePaginator
 from bot.utils import CogABCMeta, messages
@@ -226,14 +228,16 @@ async def relay_message(self, msg: Message) -> None:
 
             await self.send_header(msg)
 
-        cleaned_content = msg.clean_content
-
-        if cleaned_content:
+        if TokenRemover.find_token_in_message(msg) or WEBHOOK_URL_RE.search(msg.content):
+            cleaned_content = "Content is censored because it contains a bot or webhook token."
+        elif cleaned_content := msg.clean_content:
             # Put all non-media URLs in a code block to prevent embeds
             media_urls = {embed.url for embed in msg.embeds if embed.type in ("image", "video")}
             for url in URL_RE.findall(cleaned_content):
                 if url not in media_urls:
                     cleaned_content = cleaned_content.replace(url, f"`{url}`")
+
+        if cleaned_content:
             await self.webhook_send(
                 cleaned_content,
                 username=msg.author.display_name,


Test patch:
Repository: python-discord/bot

Issue:
Mod-alerts channel pings when large amounts of emojis are within a code block.
When a user inputs a large amount of emojis in a code block, it seems that the bot does not ignore them and proceeds to mute for emoji spam. All emojis contained within a code block should be looked over, but anything on the outside should still be scanned for amounts of emojis.

An example of what can trigger the filter:
![Untitled](https://user-images.githubusercontent.com/15021300/91444625-de5a8980-e829-11ea-9594-d38246b90651.png)




Discussion:

Resolving patch:
diff --git a/bot/rules/discord_emojis.py b/bot/rules/discord_emojis.py
--- a/bot/rules/discord_emojis.py
+++ b/bot/rules/discord_emojis.py
@@ -5,6 +5,7 @@
 
 
 DISCORD_EMOJI_RE = re.compile(r"<:\w+:\d+>")
+CODE_BLOCK_RE = re.compile(r"```.*?```", flags=re.DOTALL)
 
 
 async def apply(
@@ -17,8 +18,9 @@ async def apply(
         if msg.author == last_message.author
     )
 
+    # Get rid of code blocks in the message before searching for emojis.
     total_emojis = sum(
-        len(DISCORD_EMOJI_RE.findall(msg.content))
+        len(DISCORD_EMOJI_RE.findall(CODE_BLOCK_RE.sub("", msg.content)))
         for msg in relevant_messages
     )
 


Test patch:
Repository: python-discord/bot

Issue:
!reddit command doesn’t filter nsfw subreddits.
So yeah, as the title says `!reddit` command doesn’t filter nsfw subreddits ._.

doing: `!reddit top nsfw` displays the direct URL link to the nsfw subreddit.


Discussion:
this should be a simple fix as done here
https://github.com/python-discord/seasonalbot/blob/master/bot/exts/evergreen/reddit.py#L57
it's another Reddit command, but for `seasonalbot`

We just check if `over_18` is true or false, which will be in the response we get after sending the Http request.

the fix could be implemented at this line
https://github.com/python-discord/bot/blob/7ebc481c32cf9b7f0ee1124b22e4ed8c68de9386/bot/cogs/reddit.py#L143
Nice. Hopefully they implement this 👍 
We should keep this open until it is implemented.
I would like to finish this 
@RohanJnr I've assigned the issue to you
thanks


Resolving patch:
diff --git a/bot/exts/info/reddit.py b/bot/exts/info/reddit.py
--- a/bot/exts/info/reddit.py
+++ b/bot/exts/info/reddit.py
@@ -140,7 +140,10 @@ async def fetch_posts(self, route: str, *, amount: int = 25, params: dict = None
                 # Got appropriate response - process and return.
                 content = await response.json()
                 posts = content["data"]["children"]
-                return posts[:amount]
+
+                filtered_posts = [post for post in posts if not post["data"]["over_18"]]
+
+                return filtered_posts[:amount]
 
             await asyncio.sleep(3)
 
@@ -163,12 +166,11 @@ async def get_top_posts(self, subreddit: Subreddit, time: str = "all", amount: i
             amount=amount,
             params={"t": time}
         )
-
         if not posts:
             embed.title = random.choice(ERROR_REPLIES)
             embed.colour = Colour.red()
             embed.description = (
-                "Sorry! We couldn't find any posts from that subreddit. "
+                "Sorry! We couldn't find any SFW posts from that subreddit. "
                 "If this problem persists, please let us know."
             )
 


Test patch:
Repository: python-discord/bot

Issue:
Exclude disabled commands from the help command
Sentry Issue: [BOT-89](https://sentry.io/organizations/python-discord/issues/1867358833/?referrer=github_integration)

```
DisabledCommand: raw command is disabled
  File "bot/cogs/help.py", line 105, in command_callback
    await super().command_callback(ctx, command=command)
  File "discord/ext/commands/help.py", line 858, in command_callback
    return await self.send_group_help(cmd)
  File "bot/cogs/help.py", line 243, in send_group_help
    embed = await self.command_formatting(group)
  File "bot/cogs/help.py", line 199, in command_formatting
    if not await command.can_run(self.context):
  File "discord/ext/commands/core.py", line 1047, in can_run
    raise DisabledCommand('{0.name} command is disabled'.format(self))

Task exception was never retrieved
future: <Task finished name='Task-37481353' coro=<CustomHelpCommand.command_callback() done, defined at /bot/bot/cogs/help.py:77> exception=DisabledCommand('raw command is disabled')>
```


Discussion:

Resolving patch:
diff --git a/bot/exts/info/help.py b/bot/exts/info/help.py
--- a/bot/exts/info/help.py
+++ b/bot/exts/info/help.py
@@ -5,7 +5,7 @@
 from typing import List, Union
 
 from discord import Colour, Embed
-from discord.ext.commands import Bot, Cog, Command, Context, Group, HelpCommand
+from discord.ext.commands import Bot, Cog, Command, CommandError, Context, DisabledCommand, Group, HelpCommand
 from fuzzywuzzy import fuzz, process
 from fuzzywuzzy.utils import full_process
 
@@ -20,6 +20,8 @@
 COMMANDS_PER_PAGE = 8
 PREFIX = constants.Bot.prefix
 
+NOT_ALLOWED_TO_RUN_MESSAGE = "***You cannot run this command.***\n\n"
+
 Category = namedtuple("Category", ["name", "description", "cogs"])
 
 
@@ -173,9 +175,16 @@ async def command_formatting(self, command: Command) -> Embed:
         if aliases:
             command_details += f"**Can also use:** {aliases}\n\n"
 
-        # check if the user is allowed to run this command
-        if not await command.can_run(self.context):
-            command_details += "***You cannot run this command.***\n\n"
+        # when command is disabled, show message about it,
+        # when other CommandError or user is not allowed to run command,
+        # add this to help message.
+        try:
+            if not await command.can_run(self.context):
+                command_details += NOT_ALLOWED_TO_RUN_MESSAGE
+        except DisabledCommand:
+            command_details += "***This command is disabled.***\n\n"
+        except CommandError:
+            command_details += NOT_ALLOWED_TO_RUN_MESSAGE
 
         command_details += f"*{command.help or 'No details provided.'}*\n"
         embed.description = command_details


Test patch:
Repository: python-discord/bot

Issue:
Race condition in wait_for_deletion between a manual delete and reacting
Sentry Issue: [BOT-86](https://sentry.io/organizations/python-discord/issues/1861537034/?referrer=github_integration)

The message may be deleted before `wait_for_deletion` has a chance to add a reaction.

```
NotFound: 404 Not Found (error code: 10008): Unknown Message
  File "bot/utils/messages.py", line 38, in wait_for_deletion
    await message.add_reaction(emoji)
  File "discord/message.py", line 953, in add_reaction
    await self._state.http.add_reaction(self.channel.id, self.id, emoji)
  File "discord/http.py", line 243, in request
    raise NotFound(r, data)

Task exception was never retrieved
future: <Task finished name='Task-333258' coro=<wait_for_deletion() done, defined at /bot/bot/utils/messages.py:19> exception=NotFound('404 Not Found (error code: 10008): Unknown Message')>
```


Discussion:

Resolving patch:
diff --git a/bot/utils/messages.py b/bot/utils/messages.py
--- a/bot/utils/messages.py
+++ b/bot/utils/messages.py
@@ -34,7 +34,11 @@ async def wait_for_deletion(
 
     if attach_emojis:
         for emoji in deletion_emojis:
-            await message.add_reaction(emoji)
+            try:
+                await message.add_reaction(emoji)
+            except discord.NotFound:
+                log.trace(f"Aborting wait_for_deletion: message {message.id} deleted prematurely.")
+                return
 
     def check(reaction: discord.Reaction, user: discord.Member) -> bool:
         """Check that the deletion emoji is reacted by the appropriate user."""


Test patch:
Repository: python-discord/bot

Issue:
Null characters are not allowed in deleted message log
Sentry Issue: [BOT-8E](https://sentry.io/organizations/python-discord/issues/1877134544/?referrer=github_integration)

Not sure how a null character even got in there. Does it mean `\0`?

```
ResponseCodeError: Status: 400 Response: {'deletedmessage_set': [{'content': ['Null characters are not allowed.']}]}
(1 additional frame(s) were not displayed)
...
  File "bot/cogs/moderation/modlog.py", line 577, in on_message_delete
    botlog_url = await self.upload_log(messages=[message], actor_id=message.author.id)
  File "bot/cogs/moderation/modlog.py", line 56, in upload_log
    response = await self.bot.api_client.post(
  File "bot/api.py", line 127, in post
    return await self.request("POST", endpoint, raise_for_status=raise_for_status, **kwargs)
  File "bot/api.py", line 114, in request
    await self.maybe_raise_for_status(resp, raise_for_status)
  File "bot/api.py", line 104, in maybe_raise_for_status
    raise ResponseCodeError(response=response, response_json=response_json)

Unhandled exception in on_message_delete.
```


Discussion:

Resolving patch:
diff --git a/bot/exts/moderation/modlog.py b/bot/exts/moderation/modlog.py
--- a/bot/exts/moderation/modlog.py
+++ b/bot/exts/moderation/modlog.py
@@ -63,7 +63,7 @@ async def upload_log(
                         'id': message.id,
                         'author': message.author.id,
                         'channel_id': message.channel.id,
-                        'content': message.content,
+                        'content': message.content.replace("\0", ""),  # Null chars cause 400.
                         'embeds': [embed.to_dict() for embed in message.embeds],
                         'attachments': attachment,
                     }


Test patch: