async def add(self, ctx, *, string): """Adds quotes to a guild-specific list. Ideal formatting: "quote" - author <year>. For guild use only.""" seperator = string.rfind('-') substring = string[:seperator - 1] startIndex = substring.find('\"') if startIndex != -1: endIndex = substring.find('\"', startIndex + 1) if endIndex != -1 and len( string[seperator:].rstrip().lstrip()) > 0: quote = substring[startIndex:endIndex + 1] author = string[seperator:] access = sqlite3.connect('quotes.db') access.cursor().execute( 'INSERT INTO quotes (guild, quote, author) VALUES (?, ?, ?)', (ctx.guild.id, quote, author)) rowid = access.cursor().execute( 'SELECT rowid FROM quotes ORDER BY rowid DESC LIMIT 1' ).fetchone()[0] access.commit() access.close() embed = discord.Embed(title='Quote successfully added.', description=quote, colour=0x00FF00) embed.set_footer(text='{0} [ID: {1}]'.format(author, rowid)) await ctx.send(embed=embed) else: raise discord.InvalidArgument("Quote not properly formatted") else: raise discord.InvalidArgument("Quote not properly formatted")
def __init__(self, callback, **kwargs): self.guild_id = kwargs.get('guild') super().__init__(callback, **kwargs) del self.aliases del self.usage del self.brief del self.hidden del self.rest_is_raw del self.description del self.require_var_positional del self.ignore_extra self._max_concurency = None self.type = kwargs.get('type_', 1) if self.type != 1 and not isinstance(self.type, CommandsTypes): raise discord.InvalidArgument( 'type_ has to be interactions.CommandsTypes') self.type = int(self.type) self.default_permission = kwargs.get('default_permission', True) self.id = None if self.type == 1 and not (1 <= len(self.help) <= 100): raise discord.InvalidArgument( 'Description for a command should have 1-100 characters') if re.match(r'^[\w-]{1,32}$', self.name) is None: raise discord.InvalidArgument( 'Command names can contain only [A-Za-z0-9] and dashes or underscores' ' and have 1-32 characters')
def __init__(self, custom_id, options, placeholder=None, min_values=1, max_values=1, disabled=False, **_): if len(options) > 25: raise discord.InvalidArgument( 'options cannot have more than 25 elements') if len(options ) < max_values or min_values > max_values or min_values < 0: raise discord.InvalidArgument( 'wrong value of min_values/max_values') if (placeholder and not isinstance(placeholder, str)) or not isinstance(min_values, int) \ or not isinstance(max_values, int) or not isinstance(disabled, bool): raise TypeError('Wrong types') if not all([isinstance(option, SelectOption) for option in options]) and \ len(set((option.value for option in options))) == len(options): raise TypeError( 'All options have to be SelectOption and have unique value param' ) self.custom_id = str(custom_id) self.options = options self.placeholder = placeholder self.min_values = min_values self.max_values = max_values self.disabled = disabled
async def process_args( messageable, content, file, files ) -> Tuple[Optional[str], List[discord.File]]: if file is not None and files is not None: raise discord.InvalidArgument( "cannot pass both file and files parameter to send()" ) if file is not None: files = [file] elif files is None: files = [] if content is None: return None, files mentions = [match.group(0) for match in MENTIONS_RE.finditer(content)] ret_content = None if mentions: ret_content = ", ".join(mentions) if len(files) > 10: raise discord.InvalidArgument( "files parameter must be a list of up to 10 elements" ) if len(files) == 10: await real_send(messageable, file=await get_text_image(content)) else: files.insert(0, await get_text_image(content)) return ret_content, files
async def purgetrash(self, ctx: commands.Context, limit: converters.myint, **flags) -> None: """Works similar to a normal purge command, but instead of deleting the messages, each message is trashed. See sb!help trash for info on trashing. Can only trash up to 200 messages at once. Usage: purge <limit> <options> Options: --by: Only trash messages by this author --notby: Do not trash message by this author --contains: Only trash messages that contain this phrase. Examples: trash 50 --by @Circuit trash 50 --contains bad-word trash 50 --notby @Cool Person trash 50""" if limit > 200: raise discord.InvalidArgument( "Can only purge up to 200 messages at once") elif limit < 1: raise discord.InvalidArgument("Must purge at least 1 message") purged = {} total = 0 def check(m: discord.Message) -> bool: if flags["by"] and m.author.id != flags["by"].id: return False if flags["notby"] and m.author.id == flags["notby"].id: return False if flags["contains"] and flags["contains"] not in m.content: return False return True async for m in ctx.channel.history(limit=limit): if not check(m): continue sql_message = await starboard_funcs.orig_message(self.bot, m.id) if not sql_message: continue await utility_funcs.handle_trashing(self.bot, sql_message["id"], sql_message["guild_id"], True) purged.setdefault(m.author, 0) purged[m.author] += 1 total += 1 embed = discord.Embed( title=f"Purged {total} Messages", description="\n".join( [f"{u.name}: {c}" for u, c in purged.items()]), color=self.bot.theme_color, ) await ctx.send(embed=embed)
async def rename(self, ctx, scheme='custom', *words): size = len(ctx.guild.members) if scheme.lower().startswith('cus'): if len(words) >= size: new_names = words else: raise discord.InvalidArgument('Too few words provided') elif scheme.lower().startswith('num'): new_names = [] for i in range(1, size + 1): new_names.append(str(i)) elif scheme.lower().startswith('res'): new_names = [] for i in range(1, size + 1): new_names.append(None) elif scheme.lower().startswith('bin'): new_names = [] for i in range(1, size + 1): new_names.append(str(bin(i).replace('0b', ''))) elif scheme.lower().startswith('hex'): new_names = [] for i in range(1, size + 1): new_names.append(str(hex(i).replace('0x', ''))) elif scheme.lower().startswith('fuc'): new_names = [] for i in range(1, size + 1): new_names.append(str(words[0] * i)) else: try: lib_list = self.alphs[scheme] except KeyError: raise discord.InvalidArgument('Couldn\'t get Scheme') else: if len(lib_list) >= size: new_names = lib_list else: raise discord.InvalidArgument('Too few words in Library') nicks = list(new_names) forbidden = [] for m in ctx.guild.members: if m.id == self.bot.user.id: pass else: name = nicks[0] try: await m.edit( nick=name, reason=f'{ctx.author} requested rename-madness') except: forbidden.append(m.name) else: nicks.remove(name) await ctx.send(embed=discord.Embed( title='New Nicknames!', color=(ctx.guild.get_member_named(str(self.bot.user))).color, description= f'I happily just changed everyones nicknames!\nYou can thank {ctx.author.mention} for this.\nUnfornutaly the following users coudn\'t be renamed:\n{", ".join(forbidden)}' ))
def from_pair(cls, target: Union[discord.Role, discord.User], permission: bool) -> RawCommandPermission: if not isinstance(target, (discord.Role, discord.User)): raise discord.InvalidArgument("target should be Role or User") if not isinstance(permission, bool): raise discord.InvalidArgument("permission should be bool") return RawCommandPermission( id=target.id, type=1 if isinstance(target, discord.Role) else 2, permission=permission)
def __init__(self, *components: Component): self._limit = 5 if len(components) > self._limit: raise discord.InvalidArgument( f"components must be a list of up to {self._limit} elements") if not all(isinstance(comp, Component) for comp in components): raise discord.InvalidArgument( "components must be a list of Component") super().__init__(1) self.components = list(components)
async def send(self, content=None, *, tts=False, file=None, files=None, embed=None, embeds=None, allowed_mentions=None, ephemeral=False): if not self.acked: await self.ack(ephemeral) payload = {} if files is not None and file is not None: raise discord.InvalidArgument( 'Cannot mix file and files keyword arguments.') if embeds is not None and embed is not None: raise discord.InvalidArgument( 'Cannot mix embed and embeds keyword arguments.') if embeds is not None: if len(embeds) > 10: raise discord.InvalidArgument( 'embeds has a maximum of 10 elements.') payload['embeds'] = [e.to_dict() for e in embeds] if embed is not None: payload['embeds'] = [embed.to_dict()] if content is not None: payload['content'] = str(content) if ephemeral: payload['flags'] = 1 << 6 payload['tts'] = tts previous_mentions = getattr(self._state, 'allowed_mentions', None) if allowed_mentions: if previous_mentions is not None: payload['allowed_mentions'] = previous_mentions.merge( allowed_mentions).to_dict() else: payload['allowed_mentions'] = allowed_mentions.to_dict() elif previous_mentions is not None: payload['allowed_mentions'] = previous_mentions.to_dict() return await self._webhook._adapter.execute_webhook(wait=True, file=file, files=files, payload=payload)
async def convert(self, ctx: commands.Context, arg: str) -> None: link_pattern = "^https://discord.com/channels/[0-9]+/[0-9]+/[0-9]+" special_id_pattern = "^[0-9]+-[0-9]*[0-9]$" normal_id_pattern = "^[0-9][0-9]+[0-9]$" channel_id: int = None message_id: int = None message: discord.Message = None if arg == "^": try: message = (await ctx.channel.history(limit=2).flatten())[1] except discord.Forbidden: raise discord.Forbidden( "I can't read the messae history of this channel, " "so I don't know what message you want me to force.") elif re.match(normal_id_pattern, arg): channel_id = ctx.channel.id message_id = int(arg) elif re.match(link_pattern, arg): split = arg.split("/") channel_id = int(split[-2]) message_id = int(split[-1]) elif re.match(special_id_pattern, arg): split = arg.split("-") channel_id = int(split[0]) message_id = int(split[1]) else: raise discord.InvalidArgument( f"The argument, `{arg}`, does not appear to be " "a message link.") if not message: channel = ctx.guild.get_channel(channel_id) if not channel: raise discord.InvalidArgument( "I couldn't find a channel with the id " f"`{channel_id}`. Please make sure the message " "link is valid, and is in this server.") try: message = await channel.fetch_message(message_id) except discord.NotFound: raise discord.InvalidArgument( "I couldn't find a message that matches " f"the link `{arg}`. Please make sure the " "message link is valid.") except discord.Forbidden: raise discord.Forbidden( "I don't have permission to read message history " f"in {channel.mention}, so I can't fetch the message " f"`{arg}`") return message
def icon_url_as(self, *, format='webp', size=1024): if not discord.utils.valid_icon_size(size): raise discord.InvalidArgument( "size must be a power of 2 between 16 and 1024") if format not in discord.guild.VALID_ICON_FORMATS: raise discord.InvalidArgument("format must be one of {0}".format( discord.guild.VALID_ICON_FORMATS)) if self.icon is None: return '' return 'https://cdn.discordapp.com/icons/{0.id}/{0.icon}.{1}?size={2}'.format( self, format, size)
async def add_prefix( self, ctx: commands.Context, prefix: str, **options ) -> None: """Adds a prefix. Usage: prefixes add <prefix> <options> Options: --space: Wether or not to add a space at the end of the prefix. Examples: sb!prefixes add star --space sb!prefixes add sb? """ if options["space"] is True: prefix += " " if len(prefix) > 8: raise discord.InvalidArgument( f"`{prefix}` is too long (max length is 8 characters)." ) guild = await self.bot.db.get_guild(ctx.guild.id) if prefix in guild["prefixes"]: raise errors.AlreadyExists(f"`{prefix}` is already a prefix.") new_prefixes = guild["prefixes"] + [prefix] await self.bot.db.execute( """UPDATE guilds SET prefixes=$1 WHERE id=$2""", new_prefixes, ctx.guild.id, ) await ctx.send(f"Added `{prefix}` to the prefixes.")
def extract_user_id(input_id: str) -> str: """ Validate and extract a user ID from an input (@mention, raw user ID, etc.). This method is intended to validate and sanitise an input provided by a user, e.g., over a command. It can accept: * Raw ID: '123456789012345678' * Mentions: * No nickname: '<@123456789012345678>' * User has nickname: '<@!123456789012345678>' * Attempts to provide a raw ID: * '@123456789012345678' * '@!123456789012345678' * '!123456789012345678' * Various errors: * <@123456789012345678 * 123456789012345678> * etc. User ID parameters from: https://github.com/Rapptz/discord.py/blob/1863a1c6636f53592519320a173ec9573c090c0b/discord/ext/commands/converter.py#L83 :param input_id: The raw input ID. :return: The extracted user ID (numerical string). :raise discord.InvalidArgument: id is not a recognised user ID format """ try: return _re_user_id.fullmatch(input_id).group(1) except AttributeError: # no match - fullmatch() returned None raise discord.InvalidArgument( 'Invalid user ID format {!r}'.format(input_id))
async def test_add_emoji_role_pair_invalid_argument(mocker): """Adds a emoji/role pair to the role message creation, but the emoji is an InvalidArgument.""" cog, mock_bot, _ = init_mocks() mock_message = tosurnament_mock.DEFAULT_MESSAGE_MOCK mock_message.add_reaction = mocker.AsyncMock(side_effect=discord.InvalidArgument()) await cog.add_emoji_role_pair(cog, tosurnament_mock.CtxMock(mock_bot, message=mock_message), "🛎️", None) cog.send_reply.assert_called_once_with(mocker.ANY, "invalid_emoji", "🛎️")
def auto_rows(*buttons: Button, max_in_row: int = 5) -> List[ActionRow]: """ Distributes buttons across multiple rows and returns the list of rows. Example ------- :: rows = auto_rows( Button(label="Red", custom_id="red", style=4), Button(label="Green", custom_id="green", style=3), max_in_row=1 ) await ctx.send("Buttons", components=rows) Parameters ---------- buttons : List[:class:`Button`] a list of buttons to distribute max_in_row : :class:`int` limit of buttons in a single row. Must be between 1 and 5. Returns ------- List[:class:`ActionRow`] the list of rows with buttons """ if not (1 <= max_in_row <= 5): raise discord.InvalidArgument( "max_in_row parameter should be between 1 and 5.") return [ ActionRow(*buttons[i:i + max_in_row]) for i in range(0, len(buttons), max_in_row) ]
def getEmojiCustom(self, emojiID: str) -> discord.Emoji: for emoji in self.bot.get_all_emojis(): if emoji.id == emojiID: return emoji raise discord.InvalidArgument( f"Argument 'emojiID' ({emojiID}) does not" " reference a valid custom emoji.")
def __init__(self, custom_id, callback): if len(custom_id) > 100: raise discord.InvalidArgument( 'custom_id cannot be longer than 100 characters') if not inspect.iscoroutinefunction(callback): raise TypeError('component callback has to be a coroutine') self.custom_id = str(custom_id) self.callback = callback
def __init__(self, style, label=None, emoji=None, url=None, disabled=False, custom_id=None, **_): if not isinstance(style, ButtonStyle): raise TypeError('style has to be one of ButtonStyle') if label and len(label) > 80: raise discord.InvalidArgument( 'label cannot be longer than 80 characters') if emoji and not isinstance( emoji, (discord.PartialEmoji, str, discord.Emoji)): raise TypeError('emoji has to be the type of PartialEmoji') elif emoji: if isinstance(emoji, str): emoji = discord.PartialEmoji(name=emoji) elif isinstance(emoji, discord.Emoji): emoji = discord.PartialEmoji(name=emoji.name, animated=emoji.animated, id=emoji.id) if not isinstance(disabled, bool): raise TypeError('disabled must be boolean') if url and style is not ButtonStyle.Link: raise discord.InvalidArgument( 'url cannot be passed when not using Link style') elif not url and style is ButtonStyle.Link: raise discord.InvalidArgument( 'url nas to be passed when using Link style') if not custom_id and style is not ButtonStyle.Link: raise discord.InvalidArgument( 'custom_id has to be passed when not using Link style') if url and custom_id: raise discord.InvalidArgument( 'cannot provide both custom_id and url') self.custom_id = str(custom_id) self.disabled = disabled self.url = url self.style = style self.label = label self.emoji = emoji
def team_name_validator(self, team): """ Raises discord.InvalidArgument if team is not one of "instinct", "mystic", or "valor", case-insensitive. :param team: :return: """ if team.lower() not in ("instinct", "mystic", "valor"): raise discord.InvalidArgument('team must be one of "instinct", "mystic", or "valor" (case-insensitive)')
async def respond(self, content=None, *, embed=None, embeds=None, tts=False, allowed_mentions=None, ephemeral=False): state = self._state content = str(content) if content is not None else None if embeds is not None and embed is not None: raise discord.InvalidArgument( 'Cannot mix embed and embeds keyword arguments.') if embeds is not None: if len(embeds) > 10: raise discord.InvalidArgument( 'embeds has a maximum of 10 elements.') embeds = [e.to_dict() for e in embeds] if embed is not None: embed = embed.to_dict() if allowed_mentions is not None: if state.allowed_mentions is not None: allowed_mentions = state.allowed_mentions.merge( allowed_mentions).to_dict() else: allowed_mentions = allowed_mentions.to_dict() else: allowed_mentions = state.allowed_mentions and state.allowed_mentions.to_dict( ) if self.acked: raise discord.ClientException('Response already created') self.acked = True await state.http.respond_interaction(self.token, self.id, content, tts=tts, embed=embed, embeds=embeds, allowed_mentions=allowed_mentions, ephemeral=ephemeral)
async def reload(self, *, extension: str): if extension not in extensions: raise discord.InvalidArgument( '%s is not a valid extension to reload, the valid ones are: %s' % (extension, ', '.join(extensions))) package = make_extension_import(extension) bot = self.bot bot.unload_extension(package) bot.load_extension(package) await bot.say('Reloaded %s extension' % extension)
async def add_xp_role(bot: commands.Bot, role: discord.Role, req_xp: int) -> None: if not await functions.can_manage_role(bot, role): raise discord.InvalidArgument("I can't manage that role, " "probably because that role " "is higher than my top role.") limit = await functions.get_limit(bot, 'xproles', role.guild.id) if limit is False: raise errors.NoPremiumError("Non-premium guilds do not have " "access to XP Roles. See the last " "page of `sb!tutorial` for more info.") conn = bot.db.conn async with bot.db.lock: async with conn.transaction(): current_num = await conn.fetchval( """SELECT COUNT(*) FROM xproles WHERE guild_id=$1""", role.guild.id) if current_num + 1 > limit: raise errors.NoPremiumError( "You have reached your limit for XP Roles.") if await is_pr(bot, role.id): raise discord.InvalidArgument("A role cannot be both a Position Role " "and an XP Role.") if not 0 <= req_xp < 100000: raise discord.errors.InvalidArgument( "Required XP must be greater than or " "equal to 0 and less than 100,000") create_xp_role = \ """INSERT INTO xproles (id, guild_id, req_xp) VALUES ($1, $2, $3)""" async with bot.db.lock: async with conn.transaction(): await conn.execute(create_xp_role, role.id, role.guild.id, req_xp)
async def add_pos_role(bot: commands.Bot, role: discord.Role, max_users: int) -> None: add_role = \ """INSERT INTO posroles (id, guild_id, max_users) VALUES ($1, $2, $3)""" if not await functions.can_manage_role(bot, role): raise discord.InvalidArgument("I can't manage that role, probably " "because it is above my highest role.") limit = await functions.get_limit(bot, 'posroles', role.guild.id) if limit is False: raise errors.NoPremiumError( "Non-premium guilds do not have access " "to position-based Role Awards. See the " "last page of `sb!tutorial` for more info.") conn = bot.db.conn async with bot.db.lock: async with conn.transaction(): current_num = await conn.fetchval( """SELECT COUNT (*) FROM posroles WHERE guild_id=$1""", role.guild.id) if current_num + 1 > limit: raise errors.NoPremiumError( "You have reached your limit for Position Roles") if await is_xpr(bot, role.id): raise discord.InvalidArgument("A role cannot be both an XP Role and " "a Position Role.") async with bot.db.lock: async with conn.transaction(): await conn.execute(add_role, role.id, role.guild.id, max_users)
async def edit_role_icon( bot, role: Role, *, reason=None, icon: bytes = None, unicode_emoji: str = None, reset: bool = False, ): """|coro| Changes specified role's icon Parameters ----------- role: :class:`discord.Role` A role to edit icon: :class:`bytes` A :term:`py:bytes-like object` representing the image to upload. unicode_emoji: :class:`str` A unicode emoji to set reason: Optional[:class:`str`] The reason for editing this role. Shows up on the audit log. Raises ------- Forbidden You do not have permissions to change the role. HTTPException Editing the role failed. InvalidArgument Wrong image format passed for ``icon``. :param bot: """ if not icon and not unicode_emoji and not reset: raise discord.InvalidArgument("You must specify icon or unicode_emoji") if reset: fields = {"unicode_emoji": None, "icon": None} else: fields = { "unicode_emoji": unicode_emoji, "icon": _bytes_to_base64_data(icon) if icon else None, } r = Route("PATCH", "/guilds/{guild_id}/roles/{role_id}", guild_id=role.guild.id, role_id=role.id) await bot.http.request(r, json=fields, reason=reason)
def __init__( self, *, style: ButtonStyle, label: Optional[str] = None, emoji: Optional[Union[discord.PartialEmoji, str]] = None, custom_id: Optional[str] = None, url: Optional[str] = None, disabled: bool = False, ) -> None: global ID_SOURCE # Ugly as hell if custom_id is None: if url is None: custom_id = str(ID_SOURCE) ID_SOURCE = (ID_SOURCE + 1) % MAX_ID elif style != ButtonStyle.link: raise discord.InvalidArgument( "if you specify url, the style must be ButtonStyle.link") elif url is not None: raise discord.InvalidArgument( "you can't specify both url and custom_id") elif style == ButtonStyle.link: raise discord.InvalidArgument( "style 'link' expects url to be specified") if isinstance(emoji, str): emoji = _partial_emoji_converter(emoji) super().__init__(2) self.style = style self.label = label self.emoji = emoji self.custom_id = custom_id self.url = url self.disabled = disabled
def set_channel(self, guild, channel: discord.TextChannel, type): """ Set the screenshot or help channel for the guild. :param guild: :param channel: :param type: one of "screenshot", or "help" :return: """ if type not in ("screenshot", "help"): raise discord.InvalidArgument( 'channel type must be one of "screenshot", or "help"') self.table.update_item( Key={"guild_id": guild.id}, UpdateExpression=f"SET {type}_channel = :channel", ExpressionAttributeValues={":channel": channel.id})
async def group_add(self, ctx: NabCtx, *, name: str): """Creates a new group for members to join. The group can be a new role that will be created with this command. If the name matches an existent role, that role will become joinable. You need `Manage Roles` permissions to use this command.""" name = name.replace("\"", "") forbidden = ["add", "remove", "delete", "list"] converter = InsensitiveRole() try: role = await converter.convert(ctx, name) except commands.BadArgument: try: if name.lower() in forbidden: raise discord.InvalidArgument() role = await ctx.guild.create_role( name=name, reason="Created joinable role") except discord.Forbidden: await ctx.send( f"{ctx.tick(False)} I need `Manage Roles` permission to create a group." ) return except discord.InvalidArgument: await ctx.send(f"{ctx.tick(False)} Invalid group name.") return result = userDatabase.execute( "SELECT * FROM joinable_roles WHERE role_id = ?", (role.id, )) group = list(result) if group: await ctx.send( f"{ctx.tick(False)} Group `{role.name}` already exists.") return # Can't make joinable group a role higher than the owner's top role top_role: discord.Role = ctx.author.top_role if role >= top_role: await ctx.send( f"{ctx.tick(False)} You can't make a group with a role higher or equals than your highest." ) return userDatabase.execute( "INSERT INTO joinable_roles(server_id, role_id) VALUES(?,?)", (ctx.guild.id, role.id)) await ctx.send( f"{ctx.tick()} Group `{role.name}` created successfully.")
def _partial_emoji_converter(argument: str) -> discord.PartialEmoji: if len(argument) < 5: # Sometimes unicode emojis are actually more than 1 symbol return discord.PartialEmoji(name=argument) match = re.match(r"<(a?):([a-zA-Z0-9\_]+):([0-9]+)>$", argument) if match is not None: emoji_animated = bool(match.group(1)) emoji_name = match.group(2) emoji_id = int(match.group(3)) return discord.PartialEmoji(name=emoji_name, animated=emoji_animated, id=emoji_id) raise discord.InvalidArgument( f"Failed to convert {argument} to PartialEmoji")
def extract_role_id(input_id: str) -> str: """ Similar to :func:`~.extract_user_id` for roles. Role mentions are of the form <@&123456789012345678>. :param input_id: The raw input ID. :return: The extracted user ID (numerical string). :raise discord.InvalidArgument: id is not a recognised user ID format """ if 15 <= len(input_id) <= 23 and input_id.isnumeric(): return input_id try: return _re_role_id.fullmatch(input_id).group(1) except AttributeError: raise discord.InvalidArgument( 'Invalid role ID format {!r}'.format(input_id))
async def de(self, ctx, *users): member = ctx.message.mentions roles = ctx.message.role_mentions if len(member) == 0 and len(roles) == 0: raise discord.InvalidArgument('No Users provided') else: for r in roles: for u in r.members: member.append(u) for m in member: if m == None: continue elif m.voice.deaf: await m.edit(deafen=False, reason=f'Request for un-deaf by {ctx.author}') else: await m.edit(deafen=True, reason=f'Request for deaf by {ctx.author}')