예제 #1
0
    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.")
예제 #2
0
    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.')
예제 #3
0
    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.")
예제 #4
0
    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)
예제 #7
0
    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.")
예제 #8
0
    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)
예제 #9
0
    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.")
예제 #10
0
    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)
예제 #11
0
    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)
예제 #12
0
    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)
예제 #14
0
    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)
예제 #15
0
    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.")
예제 #16
0
    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)
예제 #18
0
    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.")