Example #1
0
async def on_message_edit(before: discord.Message, after: discord.Message):
    if not should_log(before.guild) or before.author.bot:
        return

    # Run edited message against censor.
    bad_message = await check_censor(after)
    if bad_message:
        return

    # Prevent embedding of content from triggering the log
    if before.content == after.content:
        return

    try:
        chan = client.get_channel(config.SYS_LOG)
        mes = f":pencil: **{str(before.author)}** modified in <#{before.channel.id}>: `{before.content}` to `{after.content}`"
        await message_send_helper(mes, chan)

        # If user is on watchlist, then post it there as well
        watching = watch.should_note(after.author.id)
        if watching:
            watchchan = client.get_channel(config.WATCHLIST_CHAN)
            await message_send_helper(mes, watchchan)

    except discord.errors.HTTPException as e:
        print(
            f"Unknown error with editing message. This message was unable to post for this reason: {e}\n"
        )
Example #2
0
async def on_member_update(before: discord.Member, after: discord.Member):
    if not should_log(before.guild):
        return

    # If nickname has changed
    if before.nick != after.nick:
        # If they don't have an ending nickname, they reset to their actual username
        if not after.nick:
            mes = f"**:spy: {str(after)}** has reset their username"
        else:
            mes = f"**:spy: {str(after)}** is now known as `{after.nick}`"
        chan = client.get_channel(config.SYS_LOG)
        await chan.send(mes)
    # If role quantity has changed
    elif before.roles != after.roles:
        # Determine role difference, post about it
        removed = [r.name for r in before.roles if r not in after.roles]
        added = [r.name for r in after.roles if r not in before.roles]
        mes = ""
        if removed:
            removed_str = ', '.join(removed)
            mes += f":no_entry_sign: **{str(after)}** had the role(s) `{removed_str}` removed.\n"

        if added:
            added_str = ', '.join(added)
            mes += f":new: **{str(after)}** had the role(s) `{added_str}` added."

        chan = client.get_channel(config.SYS_LOG)
        if mes != "":
            await chan.send(mes)
Example #3
0
async def on_voice_state_update(member: discord.Member,
                                before: discord.VoiceState,
                                after: discord.VoiceState):
    if not should_log(member.guild) or member.bot:
        return

    if not after.channel:
        mes = f":mute: **{str(member)}** has left voice channel {before.channel.name}"
        chan = client.get_channel(config.SYS_LOG)
        await chan.send(mes)
    elif not before.channel:
        mes = f":loud_sound: **{str(member)}** has joined voice channel {after.channel.name}"
        chan = client.get_channel(config.SYS_LOG)
        await chan.send(mes)
Example #4
0
async def check_tattletale(reaction: discord.Reaction):
    if reaction.emoji != REACTION_EMOJI or reaction.count < REACTION_THRESHOLD:
        return

    m = reaction.message
    if m.author.bot:
        return

    # If enough users have flagged a message, take the following actions:
    # - Remove the flagged message
    # - Time out the flagged user
    # - Notify staff, both of the offending message as well as who reacted, for potential abuse

    # Limited rollout: Only count reactions by users with certain role
    reactors = [x async for x in reaction.users()]
    num_valid_reactors = len([x for x in reactors if check_roles(x, TTL_ROLES)])
    if num_valid_reactors < REACTION_THRESHOLD:
        return
    reactor_list = "\n".join([str(x) for x in reactors])

    if not m.author.is_timed_out():
        await m.author.timeout(timedelta(minutes=TIMEOUT_MIN))

    try:
        await m.delete()
        msg_txt = combine_message(m)

        staff_chan = client.get_channel(MAILBOX)
        report = f"Users have flagged a message by <@{m.author.id}> in <#{m.channel.id}>: {msg_txt}.\n\nThese are the users who flagged:\n {reactor_list}"
        await staff_chan.send(report)
    except discord.NotFound:
        pass
Example #5
0
async def on_member_join(member: discord.Member):
    if not should_log(member.guild):
        return

    mes = f":confetti_ball: **{str(member)} ({member.id})** has joined"
    chan = client.get_channel(config.SYS_LOG)
    await chan.send(mes)
Example #6
0
async def delete_message_helper(message: discord.Message):
    mes = f":no_mobile_phones: **{str(message.author)}** deleted in <#{message.channel.id}>: `{message.content}`"
    chan = client.get_channel(config.SYS_LOG)
    # Adds URLs for any attachments that were included in deleted message
    # These will likely become invalid, but it's nice to note them anyway
    if message.attachments != []:
        for item in message.attachments:
            mes += '\n' + item.url

    await message_send_helper(mes, chan)
Example #7
0
async def on_reaction_remove(reaction: discord.Reaction, user: discord.Member):
    if user.bot:
        return

    emoji_name = reaction.emoji if type(
        reaction.emoji) == str else reaction.emoji.name
    chan = client.get_channel(config.SYS_LOG)
    await chan.send(
        f":face_in_clouds: {str(user)} ({user.id}) removed the `{emoji_name}` emoji"
    )
Example #8
0
async def on_member_remove(member: discord.Member):
    if not should_log(member.guild):
        return

    # We can remove left users from our answering machine
    commands.am.remove_entry(member.id)

    # Remember that the user has left, in case we want to log after they're gone
    username = f"{str(member)}"
    commands.ul.add_ban(member.id, username)
    mes = f":wave: **{username} ({member.id})** has left"
    chan = client.get_channel(config.SYS_LOG)
    await chan.send(mes)
Example #9
0
async def on_member_ban(server: discord.Guild, member: discord.Member):
    if not should_log(server):
        return

    # We can remove banned user from our answering machine and watch list (if they exist)
    commands.am.remove_entry(member.id)
    watch.remove_user(member.id)

    # Keep a record of their banning, in case the log is made after they're no longer here
    username = f"{str(member)}"
    commands.ul.add_ban(member.id, username)
    mes = f":newspaper2: **{username} ({member.id})** has been banned."
    chan = client.get_channel(config.SYS_LOG)
    await chan.send(mes)
Example #10
0
async def on_ready():
    print('Logged in as')
    print(client.user.name)
    print(client.user.id)

    # Set Bouncer's activity status
    activity_object = discord.Activity(name="for your reports!",
                                       type=discord.ActivityType.watching)
    await client.change_presence(activity=activity_object)

    spam.set_channel()

    # Upload our DB file to a private channel as a backup
    if not dbg.is_debug_bot():
        chan = client.get_channel(config.LOG_CHAN)
        currentTime = datetime.now(timezone.utc)
        filename = f"bouncer_backup_{commonbot.utils.format_time(currentTime)}.db"
        with open(config.DATABASE_PATH, 'rb') as db_file:
            await chan.send(file=discord.File(db_file, filename=filename))
Example #11
0
async def on_message(message: discord.Message):
    # Bouncer should not react to its own messages
    if message.author.id == client.user.id:
        return

    try:
        # Allows the owner to enable debug mode
        if dbg.check_toggle(message):
            await dbg.toggle_debug(message)
            return

        if dbg.should_ignore_message(message):
            return

        # If bouncer detects a private DM sent to it
        if type(message.channel) is discord.channel.DMChannel:
            # Store who the most recent user was, for $reply ^
            commands.am.set_recent_reply(message.author)

            content = commonbot.utils.combine_message(message)
            # If not blocked, send message along to specified mod channel
            if not commands.bu.is_in_blocklist(message.author.id):
                mes = ""
                chan = None
                # If we share the main server, treat that as a DM
                if config.HOME_SERVER in [
                        x.id for x in message.author.mutual_guilds
                ]:
                    mes = f"<@{message.author.id}>: {content}"
                    chan = client.get_channel(config.MAILBOX)
                # The only other server we should share is the ban appeal server
                else:
                    mes = f"{str(message.author)} ({message.author.id}): {content}"
                    chan = client.get_channel(config.BAN_APPEAL)

                logMes = await chan.send(mes)

                # Send them a message so they know something actually happened
                await message.channel.send("Your message has been forwarded!")

                # Lets also add/update them in answering machine
                mes_entry = AnsweringMachineEntry(f"{str(message.author)}",
                                                  message.created_at, content,
                                                  logMes.jump_url)
                commands.am.update_entry(message.author.id, mes_entry)
            return

        # Remove spam
        spam_message = await spam.check_spammer(message)
        if spam_message:
            return

        # Run message against censor
        bad_message = await check_censor(message)
        if bad_message:
            return

        # Check if user is on watchlist, and should be tracked
        watching = watch.should_note(message.author.id)
        if watching:
            chan = client.get_channel(config.WATCHLIST_CHAN)
            content = commonbot.utils.combine_message(message)
            mes = f"**{str(message.author)}** (ID: {message.author.id}) said in <#{message.channel.id}>: {content}"
            await message_send_helper(mes, chan)

        # If a user pings bouncer, log into mod channel, unless it's us
        if client.user in message.mentions and message.channel.category_id not in config.INPUT_CATEGORIES:
            content = commonbot.utils.combine_message(message)
            mes = f"**{str(message.author)}** (ID: {message.author.id}) pinged me in <#{message.channel.id}>: {content}\n{message.jump_url}"
            chan = client.get_channel(config.MAILBOX)
            await message_send_helper(mes, chan)

        # Only allow moderators to invoke commands, and only in staff category
        if message.content.startswith(config.CMD_PREFIX):
            if commonbot.utils.check_roles(
                    message.author, config.VALID_ROLES
            ) and message.channel.category_id in config.INPUT_CATEGORIES:
                cmd = commonbot.utils.strip_prefix(message.content,
                                                   config.CMD_PREFIX)
                cmd = commonbot.utils.get_first_word(cmd)
                if cmd in FUNC_DICT:
                    func = FUNC_DICT[cmd][0]
                    arg = FUNC_DICT[cmd][1]
                    await func(message, arg)
    except discord.errors.Forbidden as e:
        if e.code == 50007:
            chan = client.get_channel(config.MAILBOX)
            logMes = await chan.send(
                "Unable to send message - Can't send messages to that user")
        else:
            print(traceback.format_exc())
    except discord.errors.HTTPException as e:
        print(traceback.format_exc())
Example #12
0
 def set_channel(self):
     self.notification = client.get_channel(SPAM_CHAN)