Пример #1
0
async def on_ready(**kargs: Any) -> None:

    inc_statistics_better(0, "on-ready", kargs["kernel_ramfs"])

    Client: discord.Client = kargs["client"]
    print(f'{Client.user} has connected to Discord!')

    # Warn if user is not bot
    if not Client.user.bot:
        print(
            "WARNING: The connected account is not a bot, as it is against ToS we do not condone user botting"
        )

    # bot start time check to not reparse timers on network disconnect
    if kargs["bot_start"] > (time.time() - 10):

        with db_hlapi(None) as db:
            mutes: List[Tuple[str, str, str, int]] = db.fetch_all_mutes()
            lost_mutes = sorted(mutes, key=lambda a: a[3])

        ts = datetime_now().timestamp()

        lost_mute_timers = [i for i in lost_mutes if 0 != i[3]]

        if lost_mute_timers:

            print(f"Lost mutes: {len(lost_mute_timers)}")
            for i in lost_mute_timers:
                if i[3] < ts:
                    await attempt_unmute(Client, i)

            lost_mute_timers = [i for i in lost_mute_timers if i[3] >= ts]
            if lost_mute_timers:
                print(
                    f"Mute timers to recover: {len(lost_mute_timers)}\nThis process will end in {round(lost_mutes[-1][3]-time.time())} seconds"
                )

                for i in lost_mute_timers:
                    await asyncio.sleep(i[3] - datetime_now().timestamp())
                    with db_hlapi(int(i[0])) as db:
                        if db.is_muted(infractionid=i[1]):
                            await attempt_unmute(Client, i)

            print("Mutes recovered")
Пример #2
0
async def log_infraction(
        message: discord.Message, client: discord.Client, user: InterfacedUser,
        moderator: InterfacedUser, i_reason: str, i_type: str, to_dm: bool,
        ramfs: lexdpyk.ram_filesystem
) -> Tuple[str, Optional[Awaitable[None]]]:
    if not message.guild:
        raise GuildScopeError("How did we even get here")

    timestamp = datetime_now()  # Infraction timestamp

    # Define db outputs scoped correctly
    generated_id: str
    log_channel: Optional[discord.TextChannel]

    with db_hlapi(message.guild.id) as db:

        # Infraction id collision test
        while db.grab_infraction(generated_id := generate_infractionid()):
Пример #3
0
async def on_message_edit(old_message: discord.Message, message: discord.Message, **kargs: Any) -> None:

    client: discord.Client = kargs["client"]
    ramfs: lexdpyk.ram_filesystem = kargs["ramfs"]
    kernel_ramfs: lexdpyk.ram_filesystem = kargs["kernel_ramfs"]

    # Ignore bots
    if parse_skip_message(client, message):
        return
    elif not message.guild:
        return

    inc_statistics_better(message.guild.id, "on-message-edit", kernel_ramfs)

    # Add to log
    with db_hlapi(message.guild.id) as db:
        message_log_str = db.grab_config("message-edit-log") or db.grab_config("message-log")

    # Skip logging if message is the same or mlog doesnt exist
    if message_log_str and not (old_message.content == message.content):
        if message_log := client.get_channel(int(message_log_str)):

            if not isinstance(message_log, discord.TextChannel):
                return

            lim: int = constants.embed.field.value

            message_embed = discord.Embed(title=f"Message edited in #{message.channel}", color=load_embed_color(message.guild, embed_colors.edit, ramfs))
            message_embed.set_author(name=f"{message.author} ({message.author.id})", icon_url=user_avatar_url(message.author))

            old_msg = (old_message.content or "NULL")
            message_embed.add_field(name="Old Message", value=(old_msg)[:lim], inline=False)
            if len(old_msg) > lim:
                message_embed.add_field(name="(Continued)", value=(old_msg)[lim:lim * 2], inline=False)

            msg = (message.content or "NULL")
            message_embed.add_field(name="New Message", value=(msg)[:lim], inline=False)
            if len(msg) > lim:
                message_embed.add_field(name="(Continued)", value=(msg)[lim:lim * 2], inline=False)

            message_embed.set_footer(text=f"Message ID: {message.id}")
            message_embed.timestamp = datetime_now()
            asyncio.create_task(catch_logging_error(message_log, message_embed, None))
Пример #4
0
async def on_member_update(before: discord.Member, after: discord.Member, **kargs: Any) -> None:

    inc_statistics_better(before.guild.id, "on-member-update", kargs["kernel_ramfs"])

    username_log = load_message_config(before.guild.id, kargs["ramfs"], datatypes=join_leave_user_logs)["username-log"]

    if username_log and (channel := kargs["client"].get_channel(int(username_log))):
        if before.nick == after.nick:
            return

        message_embed = discord.Embed(title="Nickname updated", color=load_embed_color(before.guild, embed_colors.edit, kargs["ramfs"]))
        message_embed.set_author(name=f"{before} ({before.id})", icon_url=user_avatar_url(before))
        message_embed.add_field(name=("Before" + " | False" * (not before.nick)), value=str(before.nick))
        message_embed.add_field(name=("After" + " | False" * (not after.nick)), value=str(after.nick))

        message_embed.timestamp = ts = datetime_now()
        message_embed.set_footer(text=f"unix: {int(ts.timestamp())}")

        await catch_logging_error(channel, message_embed)
Пример #5
0
async def avatar_function(message: discord.Message, args: List[str],
                          client: discord.Client, **kwargs: Any) -> Any:
    if not message.guild:
        return 1

    user, _ = await parse_user_member_noexcept(message,
                                               args,
                                               client,
                                               default_self=True)

    embed = discord.Embed(description=f"{user.mention}'s Avatar",
                          color=load_embed_color(message.guild,
                                                 embed_colors.primary,
                                                 kwargs["ramfs"]))
    embed.set_image(url=user_avatar_url(user))
    embed.timestamp = datetime_now()
    try:
        await message.channel.send(embed=embed)
    except discord.errors.Forbidden:
        raise lib_sonnetcommands.CommandError(constants.sonnet.error_embed)
Пример #6
0
async def query_mutedb(message: discord.Message, args: List[str],
                       client: discord.Client, **kwargs: Any) -> Any:
    if not message.guild:
        return 1

    # do page capture
    if len(args) >= 2 and args[0] in ["-p", "--page"]:
        try:
            page = int(args[1]) - 1
            if page < 0: raise ValueError
        except ValueError:
            await message.channel.send("ERROR: Invalid page")
            return 1
    else:
        page = 0

    per_page = 10

    with db_hlapi(message.guild.id) as db:
        table: List[Tuple[str, str, int]] = db.fetch_guild_mutes()

    if not table:
        await message.channel.send("No Muted users in database")
        return 0

    # Test if page is valid
    if page > len(table) // per_page:
        await message.channel.send("ERROR: Page does not exist")
        return 1

    fmt: List[str] = []

    for i in sorted(table, key=lambda i: i[2])[page:page + per_page]:
        ts = "No Unmute" if i[2] == 0 else format_duration(
            i[2] - datetime_now().timestamp())
        fmt.append(f"{i[1]}, {i[0]}, {ts}"[:150])

    LF = "\n"
    await message.channel.send(
        f"Page {page+1} / {len(table)//per_page+1}, ({len(table)} mute{'s'*(len(table)!=1)})```css\nUid, InfractionID, Unmuted in\n{LF.join(fmt)}```"
    )
Пример #7
0
async def on_member_join(member: discord.Member, **kargs: Any) -> None:

    client: discord.Client = kargs["client"]
    ramfs: lexdpyk.ram_filesystem = kargs["ramfs"]

    inc_statistics_better(member.guild.id, "on-member-join", kargs["kernel_ramfs"])

    notifier_cache = load_message_config(member.guild.id, ramfs, datatypes=join_notifier)

    issues: List[str] = []

    # Handle notifer logging
    if member.id in notifier_cache["notifier-log-users"]:
        issues.append("User")
    if abs(discord_datetime_now().timestamp() - member.created_at.timestamp()) < int(notifier_cache["notifier-log-timestamp"]):
        issues.append("Timestamp")
    if int(notifier_cache["notifier-log-defaultpfp"]) and has_default_avatar(member):
        issues.append("Default pfp")

    if issues:
        asyncio.create_task(notify_problem(member, issues, notifier_cache["regex-notifier-log"], client, ramfs))

    joinlog = load_message_config(member.guild.id, ramfs, datatypes=join_leave_user_logs)["join-log"]

    # Handle join logs
    if joinlog and (logging_channel := client.get_channel(int(joinlog))):

        embed = discord.Embed(title=f"{member} joined.", description=f"*{member.mention} joined the server.*", color=load_embed_color(member.guild, embed_colors.creation, ramfs))
        embed.set_thumbnail(url=user_avatar_url(member))

        embed.timestamp = ts = datetime_now()
        embed.set_footer(text=f"uid: {member.id}, unix: {int(ts.timestamp())}")

        embed.add_field(name="Created", value=parsedate(member.created_at), inline=True)

        if isinstance(logging_channel, discord.TextChannel):
            asyncio.create_task(catch_logging_error(logging_channel, embed))
Пример #8
0
async def on_member_remove(member: discord.Member, **kargs: Any) -> None:

    inc_statistics_better(member.guild.id, "on-member-remove", kargs["kernel_ramfs"])

    log_channels = load_message_config(member.guild.id, kargs["ramfs"], datatypes=join_leave_user_logs)

    # Try for leave-log, default to join-log
    if (joinlog := (log_channels["leave-log"] or log_channels["join-log"])):
        if logging_channel := kargs["client"].get_channel(int(joinlog)):

            # Only run if in a TextChannel
            if not isinstance(logging_channel, discord.TextChannel):
                return

            embed = discord.Embed(title=f"{member} left.", description=f"*{member.mention} left the server.*", color=load_embed_color(member.guild, embed_colors.deletion, kargs["ramfs"]))
            embed.set_thumbnail(url=user_avatar_url(member))

            embed.timestamp = ts = datetime_now()
            embed.set_footer(text=f"uid: {member.id}, unix: {int(ts.timestamp())}")

            embed.add_field(name="Created", value=parsedate(member.created_at), inline=True)
            embed.add_field(name="Joined", value=parsedate(member.joined_at), inline=True)

            await catch_logging_error(logging_channel, embed)
Пример #9
0
async def profile_function(message: discord.Message, args: List[str],
                           client: discord.Client, **kwargs: Any) -> Any:
    if not message.guild:
        return 1

    user, member = await parse_user_member_noexcept(message,
                                                    args,
                                                    client,
                                                    default_self=True)

    # Status hashmap
    status_map = {
        "online": "🟢 (online)",
        "offline": "⚫ (offline)",
        "idle": "🟡 (idle)",
        "dnd": "🔴 (dnd)",
        "do_not_disturb": "🔴 (dnd)",
        "invisible": "⚫ (offline)"
    }

    embed = discord.Embed(title="User Information",
                          description=f"User information for {user.mention}:",
                          color=load_embed_color(message.guild,
                                                 embed_colors.primary,
                                                 kwargs["ramfs"]))
    embed.set_thumbnail(url=user_avatar_url(user))
    embed.add_field(name="Username", value=str(user), inline=True)
    embed.add_field(name="User ID", value=str(user.id), inline=True)
    if member:
        embed.add_field(name="Status",
                        value=status_map[member.raw_status],
                        inline=True)
        embed.add_field(name="Highest Rank",
                        value=f"{member.top_role.mention}",
                        inline=True)
    embed.add_field(name="Created",
                    value=parsedate(user.created_at),
                    inline=True)
    if member:
        embed.add_field(name="Joined",
                        value=parsedate(member.joined_at),
                        inline=True)

    # Parse adding infraction count
    with db_hlapi(message.guild.id) as db:
        viewinfs = parse_boolean(
            db.grab_config("member-view-infractions") or "0")
        moderator = await parse_permissions(message,
                                            kwargs["conf_cache"],
                                            "moderator",
                                            verbose=False)
        if moderator or (viewinfs and user.id == message.author.id):
            embed.add_field(
                name="Infractions",
                value=f"{db.grab_filter_infractions(user=user.id, count=True)}"
            )

    embed.timestamp = datetime_now()
    try:
        await message.channel.send(embed=embed)
    except discord.errors.Forbidden:
        raise lib_sonnetcommands.CommandError(constants.sonnet.error_embed)
Пример #10
0
async def mute_user(message: discord.Message, args: List[str],
                    client: discord.Client, **kwargs: Any) -> Any:
    if not message.guild:
        return 1

    ramfs: lexdpyk.ram_filesystem = kwargs["ramfs"]
    automod: bool = kwargs["automod"]
    verbose: bool = kwargs["verbose"]

    # Grab mute time
    if len(args) >= 2:
        try:
            mutetime = MustParseDuration(args[1])
            del args[1]
        except lib_goparsers.errors.ParseFailureError:
            mutetime = 0
    else:
        mutetime = 0

    # This ones for you, curl
    if not 0 <= mutetime < 60 * 60 * 256:
        mutetime = 0

    try:
        mute_role = await grab_mute_role(message, ramfs)
        member, _, reason, infractionID, _ = await process_infraction(
            message, args, client, "mute", ramfs, automod=automod)
    except (NoMuteRole, InfractionGenerationError):
        return 1

    # Check they are in the guild
    if not member:
        await message.channel.send("User is not in this guild")
        return 1

    # Attempt to mute user
    try:
        await member.add_roles(mute_role)
    except discord.errors.Forbidden:
        await message.channel.send(
            f"{BOT_NAME} does not have permission to mute this user.")
        return 1

    if verbose and not mutetime:
        await message.channel.send(
            f"Muted {member.mention} with ID {member.id} for {reason}",
            allowed_mentions=discord.AllowedMentions.none())

    # if mutetime call db timed mute
    if mutetime:

        if verbose:
            asyncio.create_task(
                message.channel.send(
                    f"Muted {member.mention} with ID {member.id} for {format_duration(mutetime)} for {reason}",
                    allowed_mentions=discord.AllowedMentions.none()))

        # Stop other mute timers and add to mutedb
        with db_hlapi(message.guild.id) as db:
            db.unmute_user(userid=member.id)
            db.mute_user(member.id, int(datetime_now().timestamp() + mutetime),
                         infractionID)

        # Create in other thread to not block command execution
        asyncio.create_task(
            sleep_and_unmute(message.guild, member, infractionID, mute_role,
                             mutetime, ramfs))

    else:

        # When muted with no unmute add to db as 0 timestamp to unmute, program should treat 0 as invalid
        with db_hlapi(message.guild.id) as db:
            db.unmute_user(userid=member.id)
            db.mute_user(member.id, 0, infractionID)