Skip to content

Commit

Permalink
Command to easily set Game Rep permissions (#194)
Browse files Browse the repository at this point in the history
* Added a command to set rep roles automatically given a list of channel IDs

* Changed set-rep command to use *args

* Changed permission overwrite to use discord.PermissionOverwrite

* Fixed issues caused by missing permissions
  • Loading branch information
Fluxticks authored Sep 14, 2021
1 parent 351b380 commit 32e7e34
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ The list below describes the different "Cogs" of the bot, their associated comma
* Reloads the given cog.
* *This command requires your user ID to be defined in the env file under `DEV_IDS`*

#### !set-rep \<user mention> \<channel or category IDs>
* Sets the permissions for a user in the channels/categories given.
* *Requires `administrator` permission in Discord*

</details>

<details>
Expand Down
102 changes: 102 additions & 0 deletions src/esportsbot/cogs/AdminCog.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os

from discord import Member, TextChannel, CategoryChannel, PermissionOverwrite
from discord.ext import commands

devs = os.getenv("DEV_IDS").replace(" ", "").split(",")
Expand Down Expand Up @@ -110,6 +111,107 @@ async def reload_cog(self, context: commands.Context, cog_name: str):
except commands.ExtensionNotLoaded:
await context.send(f"The cog with name `{cog_name}` is not loaded.")

@commands.has_permissions(administrator=True)
@commands.command(name="set-rep")
async def set_rep_perms(self, context: commands.Context, user: Member, *args):
"""
Sets the permissions for a game rep given a list of category or channel ids.
:param context: The context of the command.
:param user: The user to give the permissions to.
"""

channel_names = []

for category in args:
try:
category_id = int(category)
discord_category = context.guild.get_channel(category_id)
if not discord_category:
discord_category = await self.bot.fetch_channel(category_id)
# First remove any existing reps/overwrites.
await self.remove_user_permissions(discord_category)
# Then add the new user's permissions.
if await self.set_rep_permissions(user, discord_category):
channel_names.append(discord_category.name)
except ValueError:
continue

response_string = str(channel_names).replace("[", "").replace("]", "").strip()
await context.send(f"Successfully set the permissions for `{user.display_name}#{user.discriminator}` "
f"in the following channels/categories: `{response_string}`")

async def remove_user_permissions(self, guild_channel):
"""
Removes permission overrides that are for specific users for a given GuildChannel.
:param guild_channel: The channel to remove any user-based permission overrides.
:return True if any user-based permissions were removed, False if this process failed.
"""
if not await self.check_editable(guild_channel):
return False

for permission_group in guild_channel.overwrites:
if isinstance(permission_group, Member):
await guild_channel.set_permissions(target=permission_group, overwrite=None)

# If the channel provided is category, go through the channels inside the category and remove the permissions.
if not isinstance(guild_channel, CategoryChannel):
return True

for channel in guild_channel.channels:
await self.remove_user_permissions(channel)

return True

async def set_rep_permissions(self, user, guild_channel):
"""
Sets the permissions of a user to those that a rep would need in the given category/channel.
:param user: The user to give the permissions to.
:param guild_channel: The GuildChannel to set the permissions of.
:return True if the permissions were set for the given user, False otherwise.
"""
if not await self.check_editable(guild_channel):
return False

overwrite = PermissionOverwrite(
view_channel=True,
manage_channels=True,
manage_permissions=True,
send_messages=True,
manage_messages=True,
connect=True,
speak=True,
mute_members=True,
deafen_members=True,
move_members=True,
)
await guild_channel.set_permissions(target=user, overwrite=overwrite)

# If the channel provided is a category, ensure that the rep can type in any announcement channels.
if not isinstance(guild_channel, CategoryChannel):
return True

for channel in guild_channel.channels:
if isinstance(channel, TextChannel) and channel.is_news():
await channel.set_permissions(target=user, send_messages=True)

return True

@staticmethod
async def check_editable(guild_channel):
"""
Checks if the bot has permission to edit the permissions of a channel.
:param guild_channel: The channel to check the permissions of.
:return: True if the bot is able to edit the permissions of the channel, else False.
"""
bot_perms = guild_channel.permissions_for(guild_channel.guild.me)
bot_overwrites = guild_channel.overwrites_for(guild_channel.guild.me)
if not bot_perms.manage_permissions:
return False
# Explicitly check for False, as None means no overwrite.
if bot_overwrites.manage_permissions is False:
return False
return True


def setup(bot):
bot.add_cog(AdminCog(bot))
6 changes: 6 additions & 0 deletions src/esportsbot/user_strings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,12 @@ description = "Unloads and then reloads the given cog. Refer to the 'load cog' c
usage = "<cog name>"
readme_url = "https://github.com/FragSoc/esports-bot#reload-cog-cog-name"

[help.set_rep]
help_string = "Sets the permissions for a game rep."
description = "By mentioning a user, and then giving a set of category or channel IDs separated by a space, this command will give the required permissions for a Game Rep for the given channels."
usage = "<user mention> <channel or category ids>"
readme_url = "https://github.com/FragSoc/esports-bot#set-rep-user-mention-channel-or-category-ids"

[help.setlogchannel]
help_string = "Sets the given channel to the logging channel."
usage = "<channel mention | channel ID>"
Expand Down

0 comments on commit 32e7e34

Please sign in to comment.