async def mute(self, ctx, member: typing.Union[discord.Member, CaseInsensitiveMember], *, reason: str = None): """Mute someone""" muted_role = discord.utils.get(ctx.guild.roles, name="Muted") if muted_role is None: try: muted_role = await ctx.guild.create_role(name="Muted") for channel in ctx.guild.text_channels: await channel.set_permissions(muted_role, send_messages=False) except discord.Forbidden: raise exceptions.ForbiddenError( exceptions.ForbiddenTask.CREATE_ROLE, detail="Muted") if muted_role is None: raise exceptions.RoleNotFoundError("Muted") if muted_role in member.roles: return await ctx.send(f":x: {member} is already muted.") if reason: if len(reason) > 400: return await ctx.send( ":x: The reason cannot be longer than 400 characters.") formatted_reason = f"Action requested by {ctx.author} ({ctx.author.id}) with reason: {reason}" else: formatted_reason = f"Action requested by {ctx.author} ({ctx.author.id}) with no specified reason." if member == ctx.author: return await ctx.send(":x: You can't mute yourself.") if member == ctx.guild.me: return await ctx.send(":x: You can't mute me.") try: await member.add_roles(muted_role, reason=formatted_reason) except discord.Forbidden: raise exceptions.ForbiddenError(exceptions.ForbiddenTask.ADD_ROLE, detail="Muted") await self.bot.safe_send_dm( target=member, reason="ban_kick_mute", message=f":zipper_mouth: You were **muted** in {ctx.guild.name}.") await ctx.send(f":white_check_mark: {member} was muted.")
async def addrole(self, ctx): """Add a role to this server's `-roles` list""" await ctx.send(":information_source: Reply with the name of the role you want to create.") flow = Flow(self.bot, ctx) role_name = await flow.get_new_role(240) if isinstance(role_name, str): await ctx.send( f":white_check_mark: I will **create a new role** on this server named `{role_name}` for this.") try: discord_role = await ctx.guild.create_role(name=role_name) except discord.Forbidden: raise exceptions.ForbiddenError(exceptions.ForbiddenTask.CREATE_ROLE, role_name) else: discord_role = role_name await ctx.send( f":white_check_mark: I'll use the **pre-existing role** named `{discord_role.name}` for this.") await ctx.send(":information_source: Reply with a short message the user should see when they get the role.") role_join_message = await flow.get_text_input(300) if not role_join_message: return await self.bot.db.execute("INSERT INTO roles (guild_id, role_id, join_message) VALUES ($1, $2, $3) " "ON CONFLICT (guild_id, role_id) DO UPDATE set join_message = $3", ctx.guild.id, discord_role.id, role_join_message) await ctx.send(f':white_check_mark: `{discord_role.name}` was added as a selfrole or its join message was ' f'updated in case the selfrole already existed.')
async def unmute(self, ctx, member: typing.Union[discord.Member, CaseInsensitiveMember]): """Unmute someone""" muted_role = discord.utils.get(ctx.guild.roles, name="Muted") if muted_role is None: raise exceptions.RoleNotFoundError("Muted") if muted_role not in member.roles: return await ctx.send(f":x: {member} is not muted.") try: await member.remove_roles( muted_role, reason=f"Action requested by {ctx.author}.") except discord.Forbidden: raise exceptions.ForbiddenError( exceptions.ForbiddenTask.REMOVE_ROLE, detail="Muted") await self.bot.safe_send_dm( target=member, reason="ban_kick_mute", message=f":innocent: You were **unmuted** in {ctx.guild.name}.") await ctx.send(f":white_check_mark: {member} was unmuted.")
async def deleterole(self, ctx, hard: typing.Optional[bool] = False, *, role: str): """Remove a selfrole from this server's `-roles` list **Usage:** `-role delete true <role>` will remove the selfrole **and** delete its Discord role `-role delete false <role>` will remove the selfrole but not delete its Discord role """ try: selfrole = await Selfrole.convert(ctx, role) except exceptions.NotFoundError: return await ctx.send(f":x: This server has no selfrole that matches `{role}`.") await self.bot.db.execute("DELETE FROM roles WHERE guild_id = $1 AND role_id = $2", ctx.guild.id, selfrole.role.id) if hard: if selfrole.role: try: await selfrole.role.delete() except discord.Forbidden: raise exceptions.ForbiddenError(exceptions.ForbiddenTask.DELETE_ROLE, detail=selfrole.role.name) await ctx.send(f":white_check_mark: The `{role}` selfrole and its Discord role were deleted.") else: await ctx.send(f":white_check_mark: The `{role}` selfrole was removed from the `-roles` list but " f"I did not delete its Discord role.")
async def deleteparty(self, ctx, hard: typing.Optional[bool] = False, *, party: PoliticalParty): """Remove a political party **Usage:** `-deleteparty true <party>` will remove the party **and** delete its Discord role `-deleteparty false <party>` will remove the party but not delete its Discord role """ name = party.role.name async with self.bot.db.acquire() as connection: async with connection.transaction(): await connection.execute( "DELETE FROM party_alias WHERE party_id = $1", party.role.id) await connection.execute("DELETE FROM parties WHERE id = $1", party.role.id) if hard: try: await party.role.delete() except discord.Forbidden: raise exceptions.ForbiddenError(ForbiddenTask.DELETE_ROLE, detail=party.role.name) await ctx.send( f':white_check_mark: `{name}` and all its aliases were deleted.')
async def join(self, ctx, *, party: PoliticalParty): """Join a political party""" if party.role in ctx.author.roles: return await ctx.send( f':x: You are already part of {party.role.name}.') if party.is_private: if party.leader is None: msg = f':x: {party.role.name} is invite-only. Ask the party leader for an invitation.' else: msg = f':x: {party.role.name} is invite-only. Ask {party.leader.mention} for an invitation.' return await ctx.send(msg) try: await ctx.author.add_roles(party.role) except discord.Forbidden: raise exceptions.ForbiddenError(ForbiddenTask.ADD_ROLE, party.role.name) if party.role.name == 'Independent': return await ctx.send( f':white_check_mark: You are now an {party.role.name}.') message = f":white_check_mark: You've joined {party.role.name}!" if party.discord_invite: message = f"{message} Now head to their Discord Server and introduce yourself: {party.discord_invite}" await ctx.send(message)
async def toggle_role(self, ctx, selfrole: Selfrole): """Assigns or removes a role from someone""" if selfrole.role not in ctx.message.author.roles: try: await ctx.message.author.add_roles(selfrole.role) except discord.Forbidden: raise exceptions.ForbiddenError(exceptions.ForbiddenTask.ADD_ROLE, selfrole.role.name) await ctx.send(selfrole.join_message) elif selfrole.role in ctx.message.author.roles: try: await ctx.message.author.remove_roles(selfrole.role) except discord.Forbidden: raise exceptions.ForbiddenError(exceptions.ForbiddenTask.REMOVE_ROLE, selfrole.role.name) await ctx.send(f":white_check_mark: The `{selfrole.role.name}` role was removed from you.")
async def say(self, ctx, *, content: str): """Make the bot say something""" try: await ctx.message.delete() except discord.Forbidden: raise exceptions.ForbiddenError( exceptions.ForbiddenTask.MESSAGE_DELETE, content) await ctx.send(content)
async def kick(self, ctx, member: typing.Union[discord.Member, CaseInsensitiveMember], *, reason: str = None): """Kick someone""" if member == ctx.author: return await ctx.send(":x: You can't kick yourself.") if member == self.bot.owner: # :) raise exceptions.ForbiddenError( exceptions.ForbiddenTask.MEMBER_KICK) if member == ctx.guild.me: return await ctx.send(":x: I can't kick myself.") if member.top_role >= ctx.author.top_role: return await ctx.send( ":x: You aren't allowed to kick someone with a higher role than yours." ) if reason: if len(reason) > 400: return await ctx.send( ":x: The reason cannot be longer than 400 characters.") formatted_reason = f"Action requested by {ctx.author} ({ctx.author.id}) with reason: {reason}" else: formatted_reason = f"Action requested by {ctx.author} ({ctx.author.id}) with no specified reason." await self.bot.safe_send_dm( target=member, reason="ban_kick_mute", message=f":boot: You were **kicked** from {ctx.guild.name}.") try: await ctx.guild.kick(member, reason=formatted_reason) except discord.Forbidden: raise exceptions.ForbiddenError( exceptions.ForbiddenTask.MEMBER_KICK) await ctx.send(f":white_check_mark: {member} was kicked.")
async def on_guild_channel_create(self, channel): muted_role = discord.utils.get(channel.guild.roles, name="Muted") if muted_role is None: try: muted_role = await channel.guild.create_role(name="Muted") except discord.Forbidden: raise exceptions.ForbiddenError( exceptions.ForbiddenTask.CREATE_ROLE, detail="Muted") await channel.set_permissions(muted_role, send_messages=False)
async def default_role_listener(self, member): if not await self.bot.checks.is_default_role_enabled(member.guild.id): return default_role = await self.bot.db.fetchval( "SELECT defaultrole_role FROM guilds WHERE id = $1", member.guild.id) default_role = member.guild.get_role(default_role) if default_role is not None: try: await member.add_roles(default_role) except discord.Forbidden: raise exceptions.ForbiddenError( exceptions.ForbiddenTask.ADD_ROLE, default_role.name)
async def on_guild_join(self, guild: discord.Guild): muted_role = discord.utils.get(guild.roles, name="Muted") if muted_role is None: try: muted_role = await guild.create_role(name="Muted") for channel in guild.text_channels: try: await channel.set_permissions(muted_role, send_messages=False) except discord.HTTPException: continue except discord.Forbidden: raise exceptions.ForbiddenError( exceptions.ForbiddenTask.CREATE_ROLE, detail="Muted")
async def leave(self, ctx, *, party: PoliticalParty): """Leave a political party""" if party.role not in ctx.author.roles: return await ctx.send(f':x: You are not part of {party.role.name}.' ) try: await ctx.author.remove_roles(party.role) except discord.Forbidden: raise exceptions.ForbiddenError(ForbiddenTask.REMOVE_ROLE, detail=party.role.name) if party.role.name == 'Independent': msg = f':white_check_mark: You are no longer an {party.role.name}.' else: msg = f':white_check_mark: You left {party.role.name}.' await ctx.send(msg)
async def clear(self, ctx, amount: int, target: typing.Union[discord.Member, CaseInsensitiveMember] = None): """Purge an amount of messages in the current channel""" if amount > 500 or amount < 0: return await ctx.send(":x: Invalid amount! The maximum is 500.") def check(message): if target: return message.author.id == target.id return True try: deleted = await ctx.channel.purge(limit=amount, check=check) except discord.Forbidden: raise exceptions.ForbiddenError(task=ForbiddenTask.MESSAGE_DELETE) await ctx.send( f':white_check_mark: Deleted **{len(deleted)}** messages.', delete_after=5)
async def unban(self, ctx, user: UnbanConverter, *, reason: str = None): """Unban someone **Example:** `-unban darthspectrum` unban by Discord username `-unban 561280863464062977` unban by Discord ID""" user_object = user user_id = user.id if user_id is None: return await ctx.send(":x: I couldn't find that person.") if reason: if len(reason) > 400: return await ctx.send( ":x: The reason cannot be longer than 400 characters.") formatted_reason = f"Action requested by {ctx.author} ({ctx.author.id}) with reason: {reason}" else: formatted_reason = f"Action requested by {ctx.author} ({ctx.author.id}) with no specified reason." try: await ctx.guild.unban(discord.Object(id=user_id), reason=formatted_reason) except discord.Forbidden: raise exceptions.ForbiddenError( exceptions.ForbiddenTask.MEMBER_BAN) except discord.HTTPException: return await ctx.send(":x: That person is not banned.") if user_object: name = str(user_object) else: name = f"The Discord user with ID `{user_id}`" await ctx.send(f":white_check_mark: {name} was unbanned.")
async def defaultrole(self, ctx): """Give every new member a specific role once they join this server""" is_default_role_enabled = await self.bot.checks.is_default_role_enabled( ctx.guild.id) current_default_role = await self.bot.db.fetchval( "SELECT defaultrole_role FROM guilds WHERE id = $1", ctx.guild.id) current_default_role = ctx.guild.get_role(current_default_role) if current_default_role is None: current_default_role = "-" else: current_default_role = current_default_role.mention embed = self.bot.embeds.embed_builder( title=f":partying_face: Default Role on {ctx.guild.name}", description=f"React with the {config.GUILD_SETTINGS_GEAR} emoji to" f" change these settings.", has_footer=False) embed.add_field(name="Enabled", value=self.emojiy_settings(is_default_role_enabled)) embed.add_field(name="Default Role", value=current_default_role) info_embed = await ctx.send(embed=embed) flow = Flow(self.bot, ctx) if await flow.gear_reaction_confirm(info_embed, 300): status_question = await ctx.send( "React with :white_check_mark: to enable the default role, or with :x: to disable the default role." ) reaction = await flow.get_yes_no_reaction_confirm( status_question, 240) if reaction is None: return if reaction: await self.bot.db.execute( "UPDATE guilds SET defaultrole = true WHERE id = $1", ctx.guild.id) await ctx.send(":white_check_mark: Enabled the default role.") await ctx.send( ":information_source: Reply with the name of the role that every " "new member should get once they join.") new_default_role = await flow.get_new_role(240) if isinstance(new_default_role, str): await ctx.send( f":white_check_mark: I will **create a new role** on this server named `{new_default_role}`" f" for the default role.") try: new_default_role_object = await ctx.guild.create_role( name=new_default_role) except discord.Forbidden: raise exceptions.ForbiddenError( exceptions.ForbiddenTask.CREATE_ROLE, new_default_role) else: new_default_role_object = new_default_role await ctx.send( f":white_check_mark: I'll use the **pre-existing role** named " f"`{new_default_role_object.name}` for the default role." ) status = await self.bot.db.execute( "UPDATE guilds SET defaultrole_role = $2 WHERE id = $1", ctx.guild.id, new_default_role_object.id) if status == "UPDATE 1": await ctx.send( f":white_check_mark: Set the default role to `{new_default_role_object.name}`." ) elif not reaction: await self.bot.db.execute( "UPDATE guilds SET defaultrole = false WHERE id = $1", ctx.guild.id) await ctx.send(":white_check_mark: Disabled the default role.") await self.bot.cache.update_guild_config_cache()
async def create_new_party(self, ctx) -> typing.Optional[PoliticalParty]: await ctx.send( ":information_source: Reply with the name of the new party you want to create." ) flow = Flow(self.bot, ctx) role_name = await flow.get_new_role(240) if isinstance(role_name, str): is_updated = False await ctx.send( f":white_check_mark: I will **create a new role** on this server named `{role_name}`" f" for the new party.") try: discord_role = await ctx.guild.create_role(name=role_name) except discord.Forbidden: raise exceptions.ForbiddenError( exceptions.ForbiddenTask.CREATE_ROLE, role_name) else: is_updated = True discord_role = role_name await ctx.send( f":white_check_mark: I'll use the **pre-existing role**" f" `{discord_role.name}` for the new party.") await ctx.send( ":information_source: Reply with the name of the party's leader or representative." ) leader = await flow.get_text_input(240) if not leader: return try: leader_member = await commands.MemberConverter().convert( ctx, leader) except commands.BadArgument: raise exceptions.MemberNotFoundError(leader) await ctx.send( ":information_source: Reply with the invite link to the party's Discord server. " "If they don't have one, just reply with gibberish.") party_invite = await flow.get_text_input(300) if not party_invite: return None discord_invite_pattern = re.compile( r"(?:https?://)?discord(?:app\.com/invite|\.gg)/?[a-zA-Z0-9]+/?") if not discord_invite_pattern.fullmatch(party_invite): party_invite = None is_private = False private_question = await ctx.send( "Should this new party be **public**, i.e. join-able by everyone? " "React with :white_check_mark: if yes, or with :x: if not.") reaction = await flow.get_yes_no_reaction_confirm( private_question, 240) if reaction is None: return None if reaction: is_private = False elif not reaction: is_private = True async with self.bot.db.acquire() as connection: async with connection.transaction(): await connection.execute( "INSERT INTO parties (id, discord_invite, is_private, leader) VALUES ($1, $2, $3, $4)" "ON CONFLICT (id) DO UPDATE SET discord_invite = $2, is_private = $3," " leader = $4 WHERE parties.id = $1", discord_role.id, party_invite, is_private, leader_member.id) await connection.execute( "INSERT INTO party_alias (alias, party_id) VALUES ($1, $2)" " ON CONFLICT DO NOTHING ", discord_role.name.lower(), discord_role.id) if not is_updated: await ctx.send( f':white_check_mark: `{discord_role.name}` was added as a new party.' ) else: await ctx.send( f':white_check_mark: `{discord_role.name}` was added as a new party or its ' f'properties were updated if it already existed.') return await PoliticalParty.convert(ctx, discord_role.id)
async def ban(self, ctx, member: BanConverter, *, reason: str = None): """Ban someone If you want to ban a user that is not in this server, use the user's ID instead. **Example:** `-ban @Das` ban by mention `-ban Queen Das` ban by nickname `-ban darthspectrum` ban by username `-ban darthspectrum#4924` ban by username#discriminator `-ban 561280863464062977` ban by ID""" if isinstance(member, discord.Member): member_object = member member_id = member.id elif isinstance(member, int): member_object = None member_id = member else: return await ctx.send(":x: I couldn't find that person.") if member_id is None: return await ctx.send(":x: I couldn't find that person.") if member_object == ctx.author: return await ctx.send(":x: You can't ban yourself.") if member_object == self.bot.owner: # :) raise exceptions.ForbiddenError( exceptions.ForbiddenTask.MEMBER_BAN) if member_object == ctx.guild.me: return await ctx.send(":x: I can't ban myself.") if member_object is not None and member_object.top_role >= ctx.author.top_role: return await ctx.send( ":x: You aren't allowed to ban someone with a higher role than yours." ) if reason: if len(reason) > 400: return await ctx.send( ":x: The reason cannot be longer than 400 characters.") formatted_reason = f"Action requested by {ctx.author} ({ctx.author.id}) with reason: {reason}" else: formatted_reason = f"Action requested by {ctx.author} ({ctx.author.id}) with no specified reason." if member_object: await self.bot.safe_send_dm( target=member_object, reason="ban_kick_mute", message=f":no_entry: You were **banned** from {ctx.guild.name}." ) try: await ctx.guild.ban(discord.Object(id=member_id), reason=formatted_reason, delete_message_days=0) except discord.Forbidden: raise exceptions.ForbiddenError( exceptions.ForbiddenTask.MEMBER_BAN) except discord.HTTPException: return await ctx.send(":x: I couldn't find that person.") if member_object: name = str(member_object) else: name = f"The Discord user with ID `{member_id}`" await ctx.send(f":white_check_mark: {name} was banned.")