Ejemplo n.º 1
0
    async def unban(self, ctx, user: UserConv, *, reason: str):
        """
        Unbans the id from the guild with a reason.
        If guild has moderation logging enabled, it is logged
        """

        try:
            embed = discord.Embed(description="Done! User Unbanned")
            embed.add_field(name="Reason", value=reason)

            mod = user_discrim(ctx.author)
            unbanned = user_discrim(user)
            clean_reason = escape_backticks(reason)
            content = f"{mod} unbanned {user.mention} ({unbanned}) with reason: `{clean_reason}`"

            await ctx.guild.unban(user, reason=f"{reason} - {mod}")
            await ctx.send(embed=embed)

            self.journal.send("member/unban",
                              ctx.guild,
                              content,
                              icon="unban",
                              user=user)

        except discord.errors.Forbidden:
            raise ManualCheckFailure(
                content="I don't have permission to unban this user")
Ejemplo n.º 2
0
    async def cleanup_text(self,
                           ctx,
                           text: str,
                           count: int,
                           channel: discord.TextChannel = None):
        """ Deletes the last <count> messages with the given text. """

        await self.check_count(ctx, count)

        if channel is None:
            channel = ctx.channel

        # Deletes the messages with the text
        text = normalize_caseless(text)
        deleted = _Counter()

        def check(message):
            if deleted < count:
                if text in normalize_caseless(message.content):
                    deleted.incr()
                    return True
            return False

        messages = await channel.purge(limit=count * 2,
                                       check=check,
                                       before=ctx.message,
                                       bulk=True)

        # Send journal events
        text = escape_backticks(text)
        causer = user_discrim(ctx.author)
        content = f"{causer} deleted {len(messages)} messages in {channel.mention} matching `{text}`"
        self.journal.send(
            "text",
            ctx.guild,
            content,
            icon="delete",
            count=count,
            channel=channel,
            messags=messages,
            text=text,
            cause=ctx.author,
        )

        obj, file = self.dump_messages(messages)
        content = f"Cleanup by {causer} in {channel.mention} of `{text}` deleted these messages:"
        self.dump.send("text",
                       ctx.guild,
                       content,
                       icon="delete",
                       messages=obj,
                       file=file)
Ejemplo n.º 3
0
 async def get_user(self, ctx, name):
     if name is None:
         return ctx.author
     else:
         conv = UserConv()
         try:
             return await conv.convert(ctx, name)
         except commands.errors.BadArgument:
             name = escape_backticks(name)
             prefix = self.bot.prefix(ctx.guild)
             embed = discord.Embed(colour=discord.Colour.red())
             embed.description = f"No user found for `{name}`. Try `{prefix}ufind`."
             raise CommandFailed(embed=embed)
Ejemplo n.º 4
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)
Ejemplo n.º 5
0
    async def softban(self, ctx, user: UserConv, *, reason: str):
        """
        Soft-bans the user from the guild with a reason.
        If guild has moderation logging enabled, it is logged

        Soft-ban is a kick that cleans up the chat
        """

        try:
            embed = discord.Embed(description="Done! User Soft-banned")
            embed.add_field(name="Reason", value=reason)

            mod = user_discrim(ctx.author)
            banned = user_discrim(user)
            clean_reason = escape_backticks(reason)
            content = f"{mod} soft-banned {user.mention} ({banned}) with reason: `{clean_reason}`"

            await ctx.guild.ban(user,
                                reason=f"{reason} - {mod}",
                                delete_message_days=1)
            await asyncio.sleep(0.1)
            await ctx.guild.unban(user, reason=f"{reason} - {mod}")
            await ctx.send(embed=embed)

            self.journal.send(
                "member/softban",
                ctx.guild,
                content,
                icon="soft",
                user=user,
                reason=reason,
                cause=ctx.author,
            )

        except discord.errors.Forbidden:
            raise ManualCheckFailure(
                content="I don't have permission to soft-ban this user")
Ejemplo n.º 6
0
async def check_name_filter(cog, name, name_type, member, only_filter=None):
    """
    Checks the given name against all filters, and enforces with a dunce.
    """

    logger.debug("Checking name: %r", name)

    if only_filter is None:
        # Check all the filters
        triggered = None
        for filter_text, (filter, filter_type) in cog.filters[member.guild].items():
            if filter.matches(name):
                if triggered is None or filter_type.value > triggered.filter_type.value:
                    triggered = FoundNameViolation(
                        filter_type=filter_type, filter_text=filter_text
                    )
    else:
        # Only check this filter
        filter_type = cog.filters[member.guild][only_filter.text][1]
        if only_filter.matches(name):
            triggered = FoundNameViolation(
                filter_type=filter_type, filter_text=only_filter.text
            )
        else:
            triggered = None

    if triggered is None:
        logger.debug("No name violations found!")
        return

    filter_type = triggered.filter_type
    filter_text = triggered.filter_text
    escaped_name = escape_backticks(name)
    escaped_filter_text = escape_backticks(filter_text)

    logger.info(
        "Punishing name filter violation (%r, level %s) by '%s' (%d)",
        filter_text,
        filter_type.value,
        member.name,
        member.id,
    )

    roles = cog.bot.sql.settings.get_special_roles(member.guild)

    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))

    severity = filter_type.level
    jail_anyways = False

    if severity >= FilterType.FLAG.level:
        logger.info("Notifying staff of filter violation")
        journal_name_violation(
            cog.journal,
            member,
            name_type,
            filter_type,
            escaped_filter_text,
            escaped_name,
        )

    if severity >= FilterType.BLOCK.level:
        logger.info("Removing bad %s from member", name_type.value)
        if name_type == NameType.USER:
            jail_anyways = True
            await member.edit(
                nick=MASK_NICK,
                reason="Hid username for violating {filter_type.value} level name filter",
            )
        elif name_type == NameType.NICK:
            await member.edit(
                nick=None,
                reason=f"Removed nickname for violating {filter_type.value} level name filter",
            )
        else:
            raise ValueError(f"Unknown value for NameType: {name_type!r}")

    if severity >= FilterType.JAIL.level or jail_anyways:
        if roles.jail is None:
            logger.info(
                "Jailing user for inappropriate name, except there is no jail role configured!"
            )
            content = f"Cannot jail {member.mention} for name violation because no jail role is set!"
            cog.journal.send("name/jail", member.guild, content, icon="warning")
        else:
            logger.info("Jailing user for inappropriate name")
            await asyncio.gather(
                message_violator(jailed=True),
                cog.bot.punish.jail(
                    member.guild, member, "Jailed for violating name filter"
                ),
            )
Ejemplo n.º 7
0
async def found_text_violation(triggered, roles):
    """
    Processes a violation of the text filter. This coroutine is responsible
    for actual enforcement, based on the filter_type.
    """

    bot = triggered.bot
    journal = triggered.journal
    message = triggered.message
    content = triggered.content
    location_type = triggered.location_type
    filter_type = triggered.filter_type
    filter_text = triggered.filter_text

    logger.info(
        "Punishing %s filter violation (%r, level %s) by '%s' (%d)",
        location_type.value,
        filter_text,
        filter_type.value,
        message.author.name,
        message.author.id,
    )

    severity = filter_type.level

    # Escape content for display
    escaped_filter_text = escape_backticks(filter_text)
    escaped_content = escape_backticks(content)

    if len(escaped_content) > 1800:
        escaped_content = escaped_content[:1800] + " ... (message too long)"

    async def message_violator():
        logger.debug("Sending message to user who violated the filter")
        response = StringBuilder(
            f"The message you posted in {message.channel.mention} violates a {location_type.value} "
            f"{filter_type.value} filter disallowing `{escaped_filter_text}`.")

        if severity >= FilterType.JAIL.level:
            if roles.jail is not None:
                response.writeln(
                    "This offense is serious enough to warrant immediate revocation of posting privileges.\n"
                    f"As such, you have been assigned the `{roles.jail.name}` role, until a moderator clears you."
                )

        await message.author.send(content=str(response))
        response.clear()

        if message.content != content:
            embed_caveat = "(including text from all embeds attached to your message)"
        else:
            embed_caveat = ""

        embed = discord.Embed(description=content)
        embed.timestamp = discord.utils.snowflake_time(message.id)
        embed.set_author(name=message.author.display_name,
                         icon_url=message.author.avatar_url)
        to_send = f"The content of the deleted message {embed_caveat} is:"
        await message.author.send(content=to_send, embed=embed)

        response.writeln("or, quoted:")
        response.writeln("```")
        response.writeln(escaped_content)
        response.writeln("```")
        response.writeln("Contact a moderator if you have questions.")
        await message.author.send(content=str(response))

    if severity >= FilterType.FLAG.level:
        logger.info("Notifying staff of filter violation")
        journal_violation(journal, "text", message, filter_type,
                          escaped_filter_text, escaped_content)

    if severity >= FilterType.BLOCK.level:
        logger.info("Deleting inappropriate message id %d and notifying user",
                    message.id)
        await asyncio.gather(message.delete(), message_violator())

    if severity >= FilterType.JAIL.level:
        if roles.jail is None:
            logger.info(
                "Jailing user for inappropriate message, except there is no jail role configured!"
            )
            content = f"Cannot jail {message.author.mention} for filter violation because no jail role is set!"
            journal.send("text/jail", message.guild, content, icon="warning")
        else:
            logger.info("Jailing user for inappropriate message")
            await bot.punish.jail(message.guild, message.author,
                                  "Jailed for violating file filter")