Exemplo n.º 1
0
    async def message_count(self, ctx, user: UserConv, *exclude: TextChannelConv):
        """
        Gets the total number of messages this user has sent in the guild.
        Text channels to exclude from the search can be added as optional arguments.
        """

        message_count, edited_count, deleted_count = self.sql.message_count(
            ctx.guild, user, exclude
        )

        descr = StringBuilder()
        descr.writeln(
            f"Found `{message_count}` message{plural(message_count)} from {user.mention}."
        )

        if message_count:
            descr.writeln(
                f"Of those, `{edited_count}` (or `{edited_count / message_count * 100:.2f}%`) are edited,\n"
                f"and `{deleted_count}` (or `{deleted_count / message_count * 100:.2f}%`) are deleted."
            )

        if hasattr(user, "joined_at"):
            descr.writeln()
            descr.writeln(
                f"They have been a member for {fancy_timedelta(user.joined_at)}."
            )

        embed = discord.Embed(colour=discord.Colour.teal())
        embed.description = str(descr)

        await ctx.send(embed=embed)
Exemplo n.º 2
0
    async def role_show(self, ctx):
        """ Shows all self-assignable roles. """

        await self.check_channel(ctx)

        assignable_roles = sorted(self.bot.sql.roles.get_assignable_roles(
            ctx.guild),
                                  key=lambda r: r.name)
        if not assignable_roles:
            prefix = self.bot.prefix(ctx.guild)
            embed = discord.Embed(colour=discord.Colour.dark_purple())
            embed.set_author(name="No self-assignable roles")
            embed.description = (
                f"Moderators can use the `{prefix}role joinable/unjoinable` "
                "commands to change this list!")
            await ctx.send(embed=embed)
            return

        embed = discord.Embed(colour=discord.Colour.dark_teal())
        embed.set_author(name="Self-assignable roles")

        descr = StringBuilder(sep=", ")
        for role in assignable_roles:
            descr.write(role.mention)
        embed.description = str(descr)
        await ctx.send(embed=embed)
Exemplo n.º 3
0
    async def log_dm_show(self, ctx, user: UserConv = None):
        """
        Displays current journal mounts for a user.
        """

        if user is None:
            user = self.bot.get_user(ctx.author.id)
        else:
            user = self.bot.get_user(user.id)

        outputs = self.bot.sql.journal.get_journals_on_user(user)
        outputs = sorted(outputs, key=lambda out: out.path)
        attributes = []
        descr = StringBuilder(f"{user.mention}:\n\n")

        for output in outputs:
            if not output.settings.recursive:
                attributes.append("exact path")

            attr_str = f'({", ".join(attributes)})' if attributes else ""
            descr.writeln(f"- `{output.path}` {attr_str}")
            attributes.clear()

        if outputs:
            embed = discord.Embed(colour=discord.Colour.teal(), description=str(descr))
            embed.set_author(name="Current journal outputs")
        else:
            embed = discord.Embed(colour=discord.Colour.dark_purple())
            embed.set_author(name="No journal outputs!")

        await ctx.send(embed=embed)
Exemplo n.º 4
0
    async def ufind(self, ctx, *, name: str):
        """
        Perform a fuzzy search to find users who match the given name.
        They are listed with the closest matches first.
        Users not in this guild are marked with a \N{GLOBE WITH MERIDIANS}.
        """

        logger.info("Running ufind on '%s'", name)
        users = await similar_users(self.bot, name)
        users_not_in_guild = (set(
            member.id for member in ctx.guild.members) if ctx.guild else set())
        descr = StringBuilder()

        for user in users:
            extra = "\N{GLOBE WITH MERIDIANS}" if user in users_not_in_guild else ""
            descr.writeln(
                f"- {user.mention} {user.name}#{user.discriminator} {extra}")

        if users:
            embed = discord.Embed(description=str(descr),
                                  colour=discord.Colour.teal())
        else:
            embed = discord.Embed(description="**No users found!**",
                                  colour=discord.Colour.red())

        await ctx.send(embed=embed)
Exemplo n.º 5
0
    async def pingable_show(self, ctx):
        """ Shows all channels where a role is pingable. """
        logger.info(
            "Displaying pingable channels and roles in guild '%s' (%d)",
            ctx.guild.name,
            ctx.guild.id,
        )

        # r[0] == current channel.
        channel_role = sorted(
            self.bot.sql.roles.get_pingable_role_channels(ctx.guild),
            key=lambda r: r[0].name,
        )

        if not channel_role:
            prefix = self.bot.prefix(ctx.guild)
            embed = discord.Embed(colour=discord.Colour.dark_purple())
            embed.set_author(name="No pingable roles in this guild")
            embed.description = (
                f"Moderators can use the `{prefix}role pingable/unpingable` "
                "commands to change this list!")
            await ctx.send(embed=embed)
            return

        embed = discord.Embed(colour=discord.Colour.dark_teal())
        embed.set_author(name="Pingable roles (channel, role)")

        descr = StringBuilder(sep="\n")
        for channel, role in channel_role:
            descr.write(f"{channel.mention}: {role.mention}")
        embed.description = str(descr)
        await ctx.send(embed=embed)
Exemplo n.º 6
0
    async def channel_set(self, ctx, *channels: TextChannelConv):
        """ Overwrites the channel(s) in the restricted role channel list to exactly this. """

        logger.info(
            "Setting channels to be used for role commands in guild '%s' (%d): [%s]",
            ctx.guild.name,
            ctx.guild.id,
            ", ".join(channel.name for channel in channels),
        )

        if not channels:
            raise CommandFailed()

        # Write new channel list to database
        with self.bot.sql.transaction():
            self.bot.sql.roles.remove_all_role_command_channels(ctx.guild)
            for channel in channels:
                self.bot.sql.roles.add_role_command_channel(ctx.guild, channel)

        # Send response
        embed = discord.Embed(colour=discord.Colour.dark_teal())
        embed.set_author(name="Set channels to be used for adding roles")
        descr = StringBuilder(sep=", ")
        for channel in channels:
            descr.write(channel.mention)
        embed.description = str(descr)
        await ctx.send(embed=embed)

        # Send journal event
        self.channel_journal(ctx.guild)
Exemplo n.º 7
0
    async def role_unjoinable(self, ctx, *roles: RoleConv):
        """ Allows a moderator to remove roles from the self-assignable group. """

        logger.info(
            "Removing joinable roles for guild '%s' (%d): [%s]",
            ctx.guild.name,
            ctx.guild.id,
            ", ".join(role.name for role in roles),
        )

        if not roles:
            raise CommandFailed()

        # Remove roles from database
        with self.bot.sql.transaction():
            for role in roles:
                self.bot.sql.roles.remove_assignable_role(ctx.guild, role)

        # Send response
        embed = discord.Embed(colour=discord.Colour.dark_teal())
        embed.set_author(name="Made roles not joinable")
        descr = StringBuilder(sep=", ")
        for role in roles:
            descr.write(role.mention)
        embed.description = str(descr)
        await ctx.send(embed=embed)

        # Send journal event
        content = f"Roles were set as not joinable: {self.str_roles(roles)}"
        self.journal.send("joinable/remove",
                          ctx.guild,
                          content,
                          icon="role",
                          roles=roles)
Exemplo n.º 8
0
    async def log_show(self, ctx, *channels: TextChannelConv):
        """
        Displays current settings for this guild.
        If channels are provided, then only outputs for those channels are fetched.
        """

        if not channels:
            channels = ctx.guild.channels

        outputs = self.bot.sql.journal.get_journals_on_channels(*channels)
        outputs = sorted(outputs, key=lambda out: out.path)
        attributes = []
        descr = StringBuilder()

        for output in outputs:
            if not output.settings.recursive:
                attributes.append("exact path")

            attr_str = f'({", ".join(attributes)})' if attributes else ""
            descr.writeln(
                f"- `{output.path}` mounted at {output.sink.mention} {attr_str}"
            )
            attributes.clear()

        if outputs:
            embed = discord.Embed(colour=discord.Colour.teal(), description=str(descr))
            embed.set_author(name="Current journal outputs")
        else:
            embed = discord.Embed(colour=discord.Colour.dark_purple())
            embed.set_author(name="No journal outputs!")

        await ctx.send(embed=embed)
Exemplo n.º 9
0
    async def log_dump(self, ctx, *, condition: str = None):
        """
        Dump previous journal events that match the given conditions to JSON.
        The condition is a Python expression with no variables but
        the following attributes:

        path: str
        ppath: PurePath
        guild: discord.Guild
        content: str
        attributes: dict
        """

        events, error_embeds = self.log_filter(ctx.guild, condition, 50)

        if error_embeds:
            await ctx.send(embed=error_embeds[0])

        buffer = StringBuilder()
        obj = [event.to_dict() for event in reversed(events)]
        json.dump(obj, buffer, ensure_ascii=True)
        file = discord.File(buffer.bytes_io(), filename="journal-events.json")

        embed = discord.Embed(colour=discord.Colour.dark_teal())
        embed.description = (
            "Uploaded journal events as JSON, see attached file. "
            "\N{WHITE UP POINTING BACKHAND INDEX}"
        )
        await ctx.send(embed=embed, file=file)
Exemplo n.º 10
0
    async def role_joinable(self, ctx, *roles: RoleConv):
        """ Allows a moderator to add roles to the self-assignable group. """

        logger.info(
            "Adding joinable roles for guild '%s' (%d): [%s]",
            ctx.guild.name,
            ctx.guild.id,
            ", ".join(role.name for role in roles),
        )

        if not roles:
            raise CommandFailed()

        # Get special roles
        special_roles = self.bot.sql.settings.get_special_roles(ctx.guild)

        # Ensure none of the roles grant any permissions
        for role in roles:
            embed = permissions.elevated_role_embed(ctx.guild, role, "error")
            if embed is not None:
                raise ManualCheckFailure(embed=embed)

            for attr in ("member", "guest", "mute", "jail"):
                if role == getattr(special_roles, attr):
                    embed = discord.Embed(colour=discord.Colour.red())
                    embed.set_author(name="Cannot add role as assignable")
                    embed.description = (
                        f"{role.mention} cannot be self-assignable, "
                        f"it is already used as the **{attr}** role!")
                    raise ManualCheckFailure(embed=embed)

        # Get roles that are already assignable
        assignable_roles = self.bot.sql.roles.get_assignable_roles(ctx.guild)

        # Add roles to database
        with self.bot.sql.transaction():
            for role in roles:
                if role not in assignable_roles:
                    self.bot.sql.roles.add_assignable_role(ctx.guild, role)

        # Send response
        embed = discord.Embed(colour=discord.Colour.dark_teal())
        embed.set_author(name="Made roles joinable")
        descr = StringBuilder(sep=", ")
        for role in roles:
            descr.write(role.mention)
        embed.description = str(descr)
        await ctx.send(embed=embed)

        # Send journal event
        content = f"Roles were set as joinable: {self.str_roles(roles)}"
        self.journal.send("joinable/add",
                          ctx.guild,
                          content,
                          icon="role",
                          roles=roles)
Exemplo n.º 11
0
    async def reapply_show(self, ctx):
        """
        Lists all roles that are reappliable.
        Reappliable roles, in addition to all punishment and self-assignable roles, are
        automatically reapplied when the member rejoins the guild.
        """

        reapply_roles = self.bot.sql.settings.get_reapply_roles(ctx.guild)
        special_roles = self.bot.sql.settings.get_special_roles(ctx.guild)

        embed = discord.Embed(colour=discord.Colour.dark_teal())
        descr = StringBuilder(sep=", ")
        has_roles = False

        # Manually set
        for role in sorted(reapply_roles, key=lambda r: r.name):
            descr.write(role.mention)
        if descr:
            embed.add_field(name="Manually designated", value=str(descr))
            has_roles = True
        else:
            embed.add_field(name="Manually designated", value="(none)")

        # Punishment roles
        descr.clear()
        if special_roles.mute_role is not None:
            descr.write(special_roles.mute_role.mention)
        if special_roles.jail_role is not None:
            descr.write(special_roles.jail_role.mention)
        if descr:
            embed.add_field(name="Punishment roles", value=str(descr))
            has_roles = True

        # Self-assignable roles
        if "SelfAssignableRoles" in self.bot.cogs:
            assignable_roles = self.bot.sql.roles.get_assignable_roles(
                ctx.guild)
            if assignable_roles:
                embed.add_field(
                    name="Self-assignable roles",
                    value=", ".join(role.mention
                                    for role in sorted(assignable_roles,
                                                       key=lambda r: r.name)),
                )
                has_roles = True

        # Send final embed
        if has_roles:
            embed.title = "\N{MILITARY MEDAL} Roles which are automatically reapplied"
        else:
            embed.colour = discord.Colour.dark_purple()

        await ctx.send(embed=embed)
Exemplo n.º 12
0
def elevated_role_embed(guild, role, level):
    """
    Takes the result of elevated_role_perms() and produces an embed listing the permissions.
    The parameter level must be 'warning' or 'error'.
    """

    elevated = elevated_role_perms(guild, role)
    if not elevated:
        return None

    if level == "warning":
        colour = discord.Colour.gold()
        icon = "\N{WARNING SIGN}"
    elif level == "error":
        colour = discord.Colour.red()
        icon = "\N{NO ENTRY}"
    else:
        raise ValueError(f"Unknown severity level: '{level}'")

    embed = discord.Embed()
    embed.colour = colour
    embed.title = f"{icon} Role gives elevated permissions"
    descr = StringBuilder()
    for location, perm in elevated:
        perm = perm.replace("_", " ").title()
        if isinstance(location, discord.Guild):
            descr.writeln(f"- {perm}")
        elif isinstance(location, discord.TextChannel):
            descr.writeln(f"- {perm} in {location.mention}")
        else:
            descr.writeln(f"- {perm} in {location.name}")
    embed.description = str(descr)
    return embed
Exemplo n.º 13
0
    async def role_unpingable(self, ctx, role: RoleConv,
                              *channels: TextChannelConv):
        logger.info(
            "Making role '%s' not pingable in guild '%s' (%d), channel(s) [%s]",
            role.name,
            ctx.guild.name,
            ctx.guild.id,
            self.str_channels(channels),
        )

        if not channels:
            raise CommandFailed()

        # See role_pingable for an explanation
        channel_role = zip(
            *self.bot.sql.roles.get_pingable_role_channels(ctx.guild))
        pingable_channels = next(channel_role, set())

        exempt_channels = []

        with self.bot.sql.transaction():
            for channel in channels:
                if channel in pingable_channels:
                    self.bot.sql.roles.remove_pingable_role_channel(
                        ctx.guild, channel, role)
                else:
                    exempt_channels.append(channel)

        if exempt_channels:
            embed = discord.Embed(colour=discord.Colour.dark_grey())
            embed.set_author(
                name="Failed to make role unpingable in channels: ")
            descr = StringBuilder(sep=", ")
            for channel in exempt_channels:
                descr.write(channel.mention)
            embed.description = str(descr)
            await ctx.send(embed=embed)
            if set(exempt_channels) == set(channels):
                raise CommandFailed()

        # Send journal event
        content = f"Role was set as not pingable in channels: {self.str_channels(channels)}, except {self.str_channels(exempt_channels)}"
        self.journal.send(
            "pingable/remove",
            ctx.guild,
            content,
            icon="role",
            role=role,
            channels=channels,
        )
Exemplo n.º 14
0
    async def sha1sum(self, ctx, *urls: str):
        """ Gives the SHA1 hashes of any files attached to the message. """

        # Check all URLs
        links = []
        for url in urls:
            match = URL_REGEX.match(url)
            if match is None:
                raise CommandFailed(content=f"Not a valid url: {url}")
            links.append(match[1])
        links.extend(attach.url for attach in ctx.message.attachments)

        # Get list of "names"
        names = list(urls)
        names.extend(attach.filename for attach in ctx.message.attachments)

        # Send error if no URLS
        if not links:
            raise CommandFailed(content="No URLs listed or files attached.")

        # Download and check files
        contents = []
        content = StringBuilder("Hashes:\n```")
        buffers = await download_links(links)
        for i, binio in enumerate(buffers):
            if binio is None:
                hashsum = SHA1_ERROR_MESSAGE
            else:
                hashsum = sha1(binio.getbuffer()).hexdigest()

            content.writeln(f"{hashsum} {names[i]}")
            if len(content) > 1920:
                contents.append(content)
                if i < len(buffers) - 1:
                    content.clear()
                    content.writeln("```")

        if len(content) > 4:
            content.writeln("```")
            contents.append(content)

        for content in contents:
            await ctx.send(content=str(content))
Exemplo n.º 15
0
    async def channel_show(self, ctx):
        """ Lists all channels that are allowed to be used for role commands. """

        all_channels = self.bot.sql.roles.get_role_command_channels(ctx.guild)
        prefix = self.bot.prefix(ctx.guild)
        if all_channels:
            embed = discord.Embed(colour=discord.Colour.dark_teal())
            embed.set_author(name="Permitted channels")
            descr = StringBuilder(sep=", ")
            for channel in all_channels:
                descr.write(channel.mention)
            embed.description = str(descr)
        else:
            embed = discord.Embed(colour=discord.Colour.dark_purple())
            embed.set_author(name="All channels are permitted")
            embed.description = (
                f"There are no restricted role channels set, so `{prefix}role add/remove` commands "
                "can be used anywhere.")

        await ctx.send(embed=embed)
Exemplo n.º 16
0
    async def uinfo(self, ctx, *, name: str = None):
        """
        Fetch information about a user, whether they are in the guild or not.
        If no argument is passed, the caller is checked instead.
        """

        user = await self.get_user(ctx, name)
        usernames, nicknames = self.bot.sql.alias.get_alias_names(
            ctx.guild, user)

        logger.info("Running uinfo on '%s' (%d)", user.name, user.id)

        # Status
        content = StringBuilder()
        if getattr(user, "status", None):
            status = ("do not disturb"
                      if user.status == discord.Status.dnd else user.status)
            content.writeln(f"{user.mention}, {status}")
        else:
            content.writeln(user.mention)

        embed = discord.Embed()
        embed.timestamp = user.created_at
        embed.set_author(name=user_discrim(user))
        embed.set_thumbnail(url=user.avatar_url)

        # User colour
        if hasattr(user, "colour"):
            embed.colour = user.colour

        embed.add_field(name="ID", value=f"`{user.id}`")
        self.uinfo_add_roles(embed, user)
        self.uinfo_add_activity(embed, user, content)

        embed.description = str(content)
        content.clear()

        self.uinfo_add_voice(embed, user)
        self.uinfo_add_aliases(embed, content, usernames, nicknames)

        # Guild join date
        if hasattr(user, "joined_at"):
            embed.add_field(name="Member for",
                            value=fancy_timedelta(user.joined_at))

        # Discord join date
        embed.add_field(name="Account age",
                        value=fancy_timedelta(user.created_at))

        # Send them
        await ctx.send(embed=embed)
Exemplo n.º 17
0
    async def remind_list(self, ctx):
        """ Lists all reminders for the current user. """

        reminders = self.bot.sql.navi.get_reminders(ctx.author)
        if reminders:
            descr = StringBuilder()
            for reminder in reminders:
                until = fancy_timedelta(reminder.timestamp)
                message = escape_backticks(reminder.message)
                descr.writeln(
                    f"ID: #`{reminder.id:05}`: in `{until}` with message: `{message}`"
                )

            embed = discord.Embed(colour=discord.Colour.dark_teal())
            embed.set_author(name=f"Reminders for {ctx.author.display_name}")
            embed.description = str(descr)
        else:
            embed = discord.Embed(colour=discord.Colour.dark_purple())
            embed.description = f"No reminders for {ctx.author.mention}"

        await ctx.send(embed=embed)
Exemplo n.º 18
0
    async def listcogs(self, ctx):
        """ Lists all currently loaded cogs. """

        content = StringBuilder("```\n")

        extensions = defaultdict(list)
        for cog_name, cog in self.bot.cogs.items():
            ext_name = cog.__module__.rsplit(".", 1)[0]
            ext_name = ext_name.rsplit(".", 1)[1]

            extensions[ext_name].append(cog_name)

        # I hate this but tree-format uses lists and tuples for some reason
        # So this takes the nice dictionary and converts it to that
        extensions = [(ext, [(cog_name, []) for cog_name in cog])
                      for ext, cog in extensions.items()]

        tree = ("futaba", [("cogs", extensions)])

        content.writeln(
            format_tree(tree,
                        format_node=itemgetter(0),
                        get_children=itemgetter(1)))
        content.writeln("```")
        await ctx.send(content=str(content))
Exemplo n.º 19
0
    async def roles(self, ctx):
        """ Lists all roles in the guild. """

        contents = []
        content = StringBuilder()

        logger.info("Listing roles within the guild")
        for role in ctx.guild.roles:
            content.writeln(
                f"- {role.mention} id: `{role.id}`, members: `{len(role.members)}`"
            )

            if len(content) > 1900:
                # Too long, break into new embed
                contents.append(str(content))

                # Start content over
                content.clear()

        if content:
            contents.append(str(content))

        for i, content in enumerate(contents):
            embed = discord.Embed(description=content,
                                  colour=discord.Colour.dark_teal())
            embed.set_footer(text=f"Page {i + 1}/{len(contents)}")
            await ctx.send(embed=embed)
Exemplo n.º 20
0
async def check_text_filter(cog, message):
    # Also check embed content
    content = StringBuilder(message.content)
    for embed in message.embeds:
        embed_dict = embed.to_dict()
        content.writeln(embed_dict.get("description", ""))
        content.writeln(embed_dict.get("title", ""))

        for field in embed_dict.get("fields", []):
            content.writeln(field.get("name", ""))
            content.writeln(field.get("value", ""))

    # This is the string we will validate against
    to_check = str(content)
    logger.debug("Content to check: %r", to_check)

    # Iterate through all guild filters
    triggered = None
    filter_groups = (
        (LocationType.GUILD, cog.filters[message.guild]),
        (LocationType.CHANNEL, cog.filters[message.channel]),
    )

    for location_type, all_filters in filter_groups:
        for filter_text, (filter, filter_type) in all_filters.items():
            if filter.matches(to_check):
                if triggered is None or filter_type.value > triggered.filter_type.value:
                    triggered = FoundTextViolation(
                        bot=cog.bot,
                        journal=cog.journal,
                        message=message,
                        content=to_check,
                        location_type=location_type,
                        filter_type=filter_type,
                        filter_text=filter_text,
                    )

    if triggered is not None:
        roles = cog.bot.sql.settings.get_special_roles(message.guild)
        await found_text_violation(triggered, roles)
Exemplo n.º 21
0
    async def rinfo(self, ctx, *, name: str = None):
        """
        Fetches and prints information about a particular role in the current guild.
        If no role is specified, it displays information about the default role.
        """

        if name is None:
            role = ctx.guild.default_role
        else:
            conv = RoleConv()
            try:
                role = await conv.convert(ctx, name)
            except commands.BadArgument:
                embed = discord.Embed(colour=discord.Colour.red())
                embed.description = (
                    f"No role found in this guild for `{escape_backticks(name)}`."
                )
                raise CommandFailed(embed=embed)

        logger.info("Running rinfo on '%s' (%d)", role.name, role.id)

        embed = discord.Embed(colour=role.colour)
        embed.timestamp = role.created_at
        embed.add_field(name="ID", value=str(role.id))
        embed.add_field(name="Position", value=str(role.position))

        descr = StringBuilder(f"{role.mention}\n")
        if role.mentionable:
            descr.writeln("Mentionable")
        if role.hoist:
            descr.writeln("Hoisted")
        if role.managed:
            descr.writeln("Managed")
        embed.description = str(descr)

        if role.members:
            max_members = 10
            members = ", ".join(
                map(lambda m: m.mention, islice(role.members, 0, max_members)))
            if len(role.members) > max_members:
                diff = len(role.members) - max_members
                members += f" (and {diff} other{plural(diff)})"
        else:
            members = "(none)"

        embed.add_field(name="Members", value=members)

        await ctx.send(embed=embed)
Exemplo n.º 22
0
 def build_reason(ctx, action, minutes, reason, past=False):
     full_reason = StringBuilder(f"{action} by {user_discrim(ctx.author)}")
     if minutes:
         full_reason.write(
             f" {'for' if past else 'in'} {minutes} minute{plural(minutes)}"
         )
     if reason:
         full_reason.write(f" with reason: {reason}")
     return str(full_reason)
Exemplo n.º 23
0
    async def log_find(self, ctx, *, condition: str = None):
        """
        List previous journal events that match the given conditions.
        The condition is a Python expression with no variables but
        the following attributes:

        path: str
        ppath: PurePath
        guild: discord.Guild
        content: str
        attributes: dict
        """

        events, error_embeds = self.log_filter(ctx.guild, condition, 10)

        if error_embeds:
            await ctx.send(embed=error_embeds[0])

        if events:
            embed = discord.Embed(colour=discord.Colour.dark_teal())
            embed.set_author(name="Matching journal events")
            descr = StringBuilder()

            embeds = []
            for event in events:
                descr.writeln(f"Path: `{event.path}`, Content: {event.content}")
                descr.writeln(f"Attributes: ```py\n{pformat(event.attributes)}\n```\n")
                if len(descr) > 1400:
                    embed.description = str(descr)
                    embeds.append(embed)
                    descr.clear()
                    embed = discord.Embed(colour=discord.Colour.dark_teal())
                    embed.set_author(name="Matched journal events")
            embed.description = str(descr)
        else:
            embed = discord.Embed(colour=discord.Colour.dark_purple())
            embed.set_author(name="No matching journal entries")
            embeds = (embed,)

        for i, embed in enumerate(embeds):
            embed.set_footer(text=f"Page {i + 1}/{len(embeds)}")
            await ctx.send(embed=embed)
Exemplo n.º 24
0
    def uinfo_add_voice(embed, user):
        if getattr(user, "voice", None):
            mute = user.voice.mute or user.voice.self_mute
            deaf = user.voice.deaf or user.voice.self_deaf

            states = StringBuilder(sep=" ")
            if mute:
                states.write("muted")
            if deaf:
                states.write("deafened")

            state = str(states) if states else "active"
            embed.add_field(name="Voice", value=state)
Exemplo n.º 25
0
    async def alert_add(self, ctx, attribute: str, relationship: str, *,
                        amount: str):
        """
        Adds a join alert with the given condition.

        Possible attributes: id, created, name, discrim, avatar, status
        Possible relationships: > >= = != < <= ~
        """

        logging.info(
            "Got request to add new join alert for '%s' (%d)",
            ctx.guild.name,
            ctx.guild.id,
        )

        try:
            key = JoinAlertKey.parse(attribute)
        except ValueError:
            raise ManualCheckFailure(content=f"Invalid attribute: {attribute}")

        try:
            op = ValueRelationship(relationship)
        except ValueError:
            raise ManualCheckFailure(
                content=f"Invalid relationship: {relationship}")

        try:
            value = key.parse_value(amount)
        except ValueError as error:
            raise ManualCheckFailure(content=str(error))

        alert = JoinAlert(ctx.guild, None, key, op, value)
        logging.info("Adding join alert: %s", alert)

        with self.bot.sql.transaction():
            self.bot.sql.welcome.add_alert(ctx.guild, alert)

        self.alerts[alert.id] = alert

        # Notify the user
        embed = discord.Embed(colour=discord.Colour.dark_teal())
        embed.set_author(name="Successfully added join alert")
        descr = StringBuilder()
        descr.writeln(f"ID: #`{alert.id:05}`, Condition: `{alert}`")
        descr.writeln(
            "To get these notifications in a channel, add a logger for path `/welcome/alert`"
        )
        embed.description = str(descr)
        await ctx.send(embed=embed)
Exemplo n.º 26
0
    async def channel_delete(self, ctx, *channels: TextChannelConv):
        """ Removes the channel(s) from the restricted role channel list. """

        logger.info(
            "Removing channels to be used for role commands in guild '%s' (%d): [%s]",
            ctx.guild.name,
            ctx.guild.id,
            ", ".join(channel.mention for channel in channels),
        )

        if not channels:
            raise CommandFailed()

        # Remove channels from database
        with self.bot.sql.transaction():
            for channel in channels:
                self.bot.sql.roles.remove_role_command_channel(
                    ctx.guild, channel)

        # Send response
        embed = discord.Embed(colour=discord.Colour.dark_teal())
        embed.set_author(name="Removed channels to be used for adding roles")

        all_channels = self.bot.sql.roles.get_role_command_channels(ctx.guild)
        descr = StringBuilder(sep=", ")
        for channel in channels:
            descr.write(channel.mention)
        embed.add_field(name="Removed", value=str(descr))

        descr.clear()
        for channel in all_channels:
            descr.write(channel.mention)
        embed.add_field(name="Remaining", value=str(descr) or "(none)")
        await ctx.send(embed=embed)

        # Send journal event
        self.channel_journal(ctx.guild)
Exemplo n.º 27
0
    async def tracker_blacklist_show(self, ctx):
        """ Shows all blacklist entries for this guild.  """

        blacklist = self.bot.sql.settings.get_tracking_blacklist(ctx.guild)

        if not blacklist.blacklisted_users and not blacklist.blacklisted_channels:
            prefix = self.bot.prefix(ctx.guild)
            embed = discord.Embed(colour=discord.Colour.dark_purple())
            embed.set_author(name="No blacklist entries")
            embed.description = (
                f"Moderators can use the `{prefix}trackerblacklist add/remove` "
                "commands to change this list!")
            await ctx.send(embed=embed)
            return

        embed = discord.Embed(colour=discord.Colour.dark_teal())
        embed.set_author(name="Blacklist entries")

        if blacklist.blacklisted_channels:
            channel_msg = StringBuilder(sep=", ")
            for channel_id in blacklist.blacklisted_channels:
                channel = discord.utils.get(ctx.guild.channels, id=channel_id)
                channel_msg.write(channel.mention)

            embed.add_field(name="Blacklisted channels", value=channel_msg)

        if blacklist.blacklisted_users:
            user_msg = StringBuilder(sep=", ")
            for user_id in blacklist.blacklisted_users:
                user = discord.utils.get(chain(ctx.guild.members,
                                               ctx.bot.users),
                                         id=user_id)
                user_msg.write(user.mention)

            embed.add_field(name="Blacklisted channels", value=user_msg)

        await ctx.send(embed=embed)
Exemplo n.º 28
0
    async def message_violator(jailed):
        response = StringBuilder(
            f"The {name_type.value} you just set violates a {filter_type.value} text filter "
            f"disallowing `{escaped_filter_text}`.\n"
        )

        if jailed:
            if roles.jail is not None:
                response.writeln(
                    f"In the mean time, you have been assigned the `{roles.jail.name}` role, "
                    "revoking your posting privileges until a moderator clears you."
                )
        else:
            response.writeln(
                "Your name has been manually cleared. Please do not set your name to "
                "anything offensive in the future."
            )

        await member.send(content=str(response))
Exemplo n.º 29
0
    async def list_emojis(self, ctx, all_guilds=False):
        contents = []
        content = StringBuilder()

        if all_guilds:
            if not mod_perm(ctx):
                raise ManualCheckFailure(
                    content="Only moderators can do this.")

            guild_emojis = (guild.emojis for guild in self.bot.guilds)
            emojis = chain(*guild_emojis)
        else:
            emojis = ctx.guild.emojis

        logger.info("Listing all emojis within the guild")
        for emoji in emojis:
            managed = "M" if emoji.managed else ""
            content.writeln(
                f"- [{emoji}]({emoji.url}) id: `{emoji.id}`, name: `{emoji.name}` {managed}"
            )

            if len(content) > 1900:
                # Too long, break into new embed
                contents.append(str(content))

                # Start content over
                content.clear()

        if content:
            contents.append(str(content))

        for i, content in enumerate(contents):
            embed = discord.Embed(description=content,
                                  colour=discord.Colour.dark_teal())
            embed.set_footer(text=f"Page {i + 1}/{len(contents)}")

            if i == 0:
                if all_guilds:
                    embed.set_author(name="Emojis in all guilds")
                else:
                    embed.set_author(name=f"Emojis within {ctx.guild.name}")

            await ctx.send(embed=embed)
Exemplo n.º 30
0
    async def alert_show(self, ctx):
        """ Lists all join alerts for this guild. """

        logging.info("Showing all join alerts for '%s' (%d)", ctx.guild.name,
                     ctx.guild.id)

        embed = discord.Embed()
        embed.set_author(name="Join alerts")
        descr = StringBuilder()
        descr.writeln("__Alert ID__ | __Condition__")

        for alert in self.alerts.values():
            assert alert.id is not None, "Alert was not given an ID"
            descr.writeln(f"#**`{alert.id:05}`** | `{alert}`")

        if self.alerts:
            embed.colour = discord.Colour.dark_teal()
            embed.description = str(descr)
        else:
            embed.colour = discord.Colour.dark_purple()
            embed.description = "No alerts for this guild"

        await ctx.send(embed=embed)