Repository: Cog-Creators/Red-DiscordBot

Issue:
[V3 Streams] Toggle Mention Permissions when live
# Feature request

<!-- This template is for feature requests. Please fill out the following: -->


#### Select the type of feature you are requesting:

<!-- To check a box, replace the space between the [] with a x -->

- [x] Cog
- [ ] Command
- [ ] API functionality

#### Describe your requested feature
Due to servers that may use streamalerts in large servers who use a role mention, If the role is not mention-able that they set for the streamalert have the bot turn on the permission for mentioning announce the stream and then turn off the permission so said permission is not mentionable 24/7
<!--
Feel free to describe in as much detail as you wish.

If you are requesting a cog to be included in core: 
    - Describe the functionality in as much detail as possible
    - Include the command structure, if possible
    - Please note that unless it's something that should be core functionality,
      we reserve the right to reject your suggestion and point you to our cog 
      board to request it for a third-party cog
      
If you are requesting a command:
    - Include what cog it should be in and a name for the command
    - Describe the intended functionality for the command
    - Note any restrictions on who can use the command or where it can be used

If you are requesting API functionality:
    - Describe what it should do
    - Note whether it is to extend existing functionality or introduce new functionality
   
-->



Discussion:

Resolving patch:
diff --git a/redbot/cogs/streams/streams.py b/redbot/cogs/streams/streams.py
--- a/redbot/cogs/streams/streams.py
+++ b/redbot/cogs/streams/streams.py
@@ -28,7 +28,7 @@
 from collections import defaultdict
 import asyncio
 import re
-from typing import Optional, List
+from typing import Optional, List, Tuple
 
 CHECK_DELAY = 60
 
@@ -396,9 +396,6 @@ async def online(self, ctx: commands.Context):
     async def role(self, ctx: commands.Context, *, role: discord.Role):
         """Toggle a role mention."""
         current_setting = await self.db.role(role).mention()
-        if not role.mentionable:
-            await ctx.send("That role is not mentionable!")
-            return
         if current_setting:
             await self.db.role(role).mention.set(False)
             await ctx.send(
@@ -408,11 +405,17 @@ async def role(self, ctx: commands.Context, *, role: discord.Role):
             )
         else:
             await self.db.role(role).mention.set(True)
-            await ctx.send(
-                _(
-                    "When a stream or community is live, `@\u200b{role.name}` will be mentioned."
-                ).format(role=role)
-            )
+            msg = _(
+                "When a stream or community is live, `@\u200b{role.name}` will be mentioned."
+            ).format(role=role)
+            if not role.mentionable:
+                msg += " " + _(
+                    "Since the role is not mentionable, it will be momentarily made mentionable "
+                    "when announcing a streamalert. Please make sure I have the correct "
+                    "permissions to manage this role, or else members of this role won't receive "
+                    "a notification."
+                )
+            await ctx.send(msg)
 
     @streamset.command()
     @commands.guild_only()
@@ -535,7 +538,7 @@ async def check_streams(self):
                         continue
                     for channel_id in stream.channels:
                         channel = self.bot.get_channel(channel_id)
-                        mention_str = await self._get_mention_str(channel.guild)
+                        mention_str, edited_roles = await self._get_mention_str(channel.guild)
 
                         if mention_str:
                             content = _("{mention}, {stream.name} is live!").format(
@@ -546,19 +549,35 @@ async def check_streams(self):
 
                         m = await channel.send(content, embed=embed)
                         stream._messages_cache.append(m)
+                        if edited_roles:
+                            for role in edited_roles:
+                                await role.edit(mentionable=False)
                         await self.save_streams()
 
-    async def _get_mention_str(self, guild: discord.Guild):
+    async def _get_mention_str(self, guild: discord.Guild) -> Tuple[str, List[discord.Role]]:
+        """Returns a 2-tuple with the string containing the mentions, and a list of
+        all roles which need to have their `mentionable` property set back to False.
+        """
         settings = self.db.guild(guild)
         mentions = []
+        edited_roles = []
         if await settings.mention_everyone():
             mentions.append("@everyone")
         if await settings.mention_here():
             mentions.append("@here")
+        can_manage_roles = guild.me.guild_permissions.manage_roles
         for role in guild.roles:
             if await self.db.role(role).mention():
+                if can_manage_roles and not role.mentionable:
+                    try:
+                        await role.edit(mentionable=True)
+                    except discord.Forbidden:
+                        # Might still be unable to edit role based on hierarchy
+                        pass
+                    else:
+                        edited_roles.append(role)
                 mentions.append(role.mention)
-        return " ".join(mentions)
+        return " ".join(mentions), edited_roles
 
     async def check_communities(self):
         for community in self.communities:
@@ -589,12 +608,15 @@ async def check_communities(self):
                         emb = await community.make_embed(streams)
                         chn_msg = [m for m in community._messages_cache if m.channel == chn]
                         if not chn_msg:
-                            mentions = await self._get_mention_str(chn.guild)
+                            mentions, roles = await self._get_mention_str(chn.guild)
                             if mentions:
                                 msg = await chn.send(mentions, embed=emb)
                             else:
                                 msg = await chn.send(embed=emb)
                             community._messages_cache.append(msg)
+                            if roles:
+                                for role in roles:
+                                    await role.edit(mentionable=False)
                             await self.save_communities()
                         else:
                             chn_msg = sorted(chn_msg, key=lambda x: x.created_at, reverse=True)[0]


Test patch: