Repository: Cog-Creators/Red-DiscordBot

Issue:
[Core] Filter roles 
Filtering roles should be done in ctx.send now that the new discord permissions will allow bots with mention everyone or administrator to ping every role. We do not filter ctx.send currently and user converter does a role mention if you send full role mention as a string. 


Discussion:

Resolving patch:
diff --git a/redbot/core/bot.py b/redbot/core/bot.py
--- a/redbot/core/bot.py
+++ b/redbot/core/bot.py
@@ -943,6 +943,7 @@ async def is_automod_immune(
     async def send_filtered(
         destination: discord.abc.Messageable,
         filter_mass_mentions=True,
+        filter_roles=True,
         filter_invite_links=True,
         filter_all_links=False,
         **kwargs,
@@ -969,6 +970,8 @@ async def send_filtered(
         content = kwargs.pop("content", None)
 
         if content:
+            if filter_roles and isinstance(destination, discord.TextChannel):
+                content = common_filters.sanitize_role_mentions(content, destination.guild.roles)
             if filter_mass_mentions:
                 content = common_filters.filter_mass_mentions(content)
             if filter_invite_links:
diff --git a/redbot/core/commands/context.py b/redbot/core/commands/context.py
--- a/redbot/core/commands/context.py
+++ b/redbot/core/commands/context.py
@@ -75,7 +75,10 @@ async def send(self, content=None, **kwargs):
             :func:`~redbot.core.utils.common_filters.filter_mass_mentions`.
             This must take a single `str` as an argument, and return
             the sanitized `str`.
-        \*\*kwargs
+        sanitize_roles : bool
+            Whether or not role mentions should be sanitized for you.
+            Defaults to ``True``
+        **kwargs
             See `discord.ext.commands.Context.send`.
 
         Returns
@@ -86,6 +89,10 @@ async def send(self, content=None, **kwargs):
         """
 
         _filter = kwargs.pop("filter", common_filters.filter_mass_mentions)
+        sanitize_roles = kwargs.pop("sanitize_roles", True)
+
+        if sanitize_roles and content and self.guild:
+            content = common_filters.sanitize_role_mentions(str(content), self.guild.roles)
 
         if _filter and content:
             content = _filter(str(content))
diff --git a/redbot/core/utils/common_filters.py b/redbot/core/utils/common_filters.py
--- a/redbot/core/utils/common_filters.py
+++ b/redbot/core/utils/common_filters.py
@@ -1,4 +1,7 @@
 import re
+from typing import Iterable
+
+import discord
 
 __all__ = [
     "URL_RE",
@@ -11,6 +14,7 @@
     "normalize_smartquotes",
     "escape_spoilers",
     "escape_spoilers_and_mass_mentions",
+    "sanitize_role_mentions",
 ]
 
 # regexes
@@ -173,3 +177,32 @@ def escape_spoilers_and_mass_mentions(content: str) -> str:
         The escaped string.
     """
     return escape_spoilers(filter_mass_mentions(content))
+
+
+def sanitize_role_mentions(content: str, roles: Iterable[discord.Role]) -> str:
+    """
+    Swaps out role mentions for @RoleName
+
+    This should always be used prior to filtering everyone mentions
+
+    Parameters
+    ----------
+    content: str
+        The string to make substitutions to
+    roles: Iterable[discord.Role]
+        The roles to make substitutions for
+
+    Returns
+    -------
+    str
+        The resulting string
+    """
+    transformations = {re.escape(fr"<@&{role.id}>"): f"@{role.name}" for role in roles}
+
+    def repl(obj):
+        return transformations.get(re.escape(obj.group(0)), "")
+
+    pattern = re.compile("|".join(transformations.keys()))
+    result = pattern.sub(repl, content)
+
+    return result


Test patch: