Пример #1
0
    async def on_message(self, msg: Message):
        # Log messages to the console/log file if enabled
        if self.bot.log_messages:
            timestamp = pretty_datetime(datetime.now(), display="TIME")
            message = f"[{msg.guild} - #{msg.channel}] <{msg.author}>: {msg.content}"

            self.bot.log.info(f"-{timestamp}- {message}")
Пример #2
0
    async def admin(self, ctx: Context):
        """Base command for server administrators.

        Run without arguments to view current server settings.
        MUST HAVE SERVER ADMINISTRATOR PERMISSION
        """
        if ctx.invoked_subcommand is not None:
            return

        sid = str(ctx.guild.id)
        log_status = None
        mute_role = None

        try:
            channel = self.bot.get_channel(int(self.db[sid]["log_channel"]))
            log_status = f"{self.db[sid]['log']}, {channel.mention}"
        except KeyError:
            log_status = "Not set up"
        try:
            role = ctx.guild.get_role(int(self.db[sid]["mute_role"]))
            mute_role = role.name
        except KeyError:
            mute_role = "Not set up"

        embed = Embed(title="Admin Info", color=0x7289DA)
        embed.add_field(name="Log", value=log_status, inline=True)
        embed.add_field(name="Mute Role", value=mute_role, inline=True)
        embed.set_footer(text=pretty_datetime(datetime.now()))

        await ctx.send(embed=embed)
Пример #3
0
    async def warns_list(self, ctx: Context, target: Member = None):
        """List all active warns of yourself or another member.
        Invoke without argument to view your own warns.
        Kick member permission required to view other Members' warns
        """
        sid = str(ctx.guild.id)

        if target is None:
            target = ctx.author

        uid = str(target.id)

        if uid not in self.warn_db[sid]:
            await ctx.send(":anger: Member has no warns.")
            return

        # This is ugly but it's 4am and I don't care
        if (
            target is not ctx.author
            and not ctx.channel.permissions_for(ctx.author).kick_members
        ):
            return

        embed = Embed(
            title=f"{target.name}#{target.discriminator}'s Warns", color=0xFF0000
        )

        warn_count = len(self.warn_db[sid][uid])

        embed.add_field(name="Total warns", value=str(warn_count), inline=False)

        for i, w in self.warn_db[sid][uid].items():
            now = datetime.now(tz=timezone.utc)
            then = datetime.fromtimestamp(float(w["expires"]), tz=timezone.utc)
            result = then - now

            expires = pretty_timedelta(result)

            issuer = ctx.guild.get_member(int(w["issued_by"]))
            name = f"{issuer.name}#{issuer.discriminator}"

            embed.add_field(
                name=i,
                value=f"By: {name}\nReason: {w['reason']}\nExpires: {expires}",
                inline=True,
            )

        embed.set_footer(text=pretty_datetime(datetime.now()))

        await ctx.send(embed=embed)
Пример #4
0
    def __init__(self, bot: DiscordBot):
        self.bot = bot
        self.name = "admin"
        self.version = VERSION
        self.backup = True

        try:
            with open("config/config.json") as cfg:
                self.backup = json.load(cfg)["BackupDB"]
        except Exception as error:
            self.bot.log.error(f"Error loading from config file:\n    - {error}")

        db_file = "db/admin.sql"

        if os.path.exists(db_file) and self.backup:
            timestamp = pretty_datetime(datetime.now(), display="FILE")
            try:
                shutil.copyfile(db_file, f"db/backups/admin-{timestamp}.sql")
            except IOError as e:
                error_file = f"db/backups/admin-{timestamp}.sql"
                self.bot.log.error(f"Unable to create file {error_file}\n    - {e}")

        self.sql_db = SqliteDict(
            filename=db_file,
            tablename="admin",
            autocommit=True,
            encode=json.dumps,
            decode=json.loads,
        )

        if "admin" not in self.sql_db:
            self.sql_db["admin"] = {}

        if "temp_bans" not in self.sql_db:
            self.sql_db["temp_bans"] = {}

        if "warns" not in self.sql_db:
            self.sql_db["warns"] = {}

        if "mutes" not in self.sql_db:
            self.sql_db["mutes"] = {}

        self.db = self.sql_db["admin"]
        self.tempban_db = self.sql_db["temp_bans"]
        self.warn_db = self.sql_db["warns"]
        self.mute_db = self.sql_db["mutes"]

        asyncio.create_task(self.task_scheduler())
Пример #5
0
def get_logger(file_name) -> logging.Logger:
    """Get an instance of Logger and set up log files."""
    timestamp = pretty_datetime(datetime.now(), "FILE")
    log_file = f"logs/{timestamp}_{file_name}"

    if not os.path.exists("logs"):
        try:
            os.makedirs("logs")
        except IOError as e:
            print(e)
            exit()

    log = logging.getLogger()
    log.setLevel(logging.INFO)
    log.addHandler(logging.FileHandler(filename=log_file, encoding="utf-8"))
    log.addHandler(logging.StreamHandler(sys.stdout))
    return log
Пример #6
0
    async def on_command(self, ctx: Context):
        # Log the command to the console/log file if enabled
        if self.bot.log_commands:
            timestamp = pretty_datetime(datetime.now(), display="TIME")

            command = ctx.message.content
            author = ctx.author

            location = f"[{ctx.guild}] - #{ctx.message.channel}"
            header = f"-{timestamp}- [COMMAND] `{command}`"

            self.bot.log.info(f"{header} by `{author}` in `{location}`")

        if self.bot.delete_cmds:
            try:
                await ctx.message.delete(delay=2)
            except Exception as e:
                self.bot.log.warning(
                    f"Unable to delete command message:\n    - {e}")
Пример #7
0
async def embed_builder(
    action: str, member: Member, reason: str, td: timedelta = None
) -> Embed:
    embed = Embed(title=action, color=0xFF0000)

    embed.add_field(name="From", value=member.guild.name)
    embed.add_field(name="Reason", value=reason, inline=False)

    try:
        embed.set_author(icon_url=member.guild.icon)
    except Exception:
        pass

    if td is not None:
        embed.add_field(name="Expires In", value=pretty_timedelta(td), inline=False)

    embed.set_footer(text=pretty_datetime(datetime.now()))

    return embed
Пример #8
0
    async def log_to_channel(self, ctx: Context, target: Member, info: str = None):
        """Send an embed-formatted log of an event to a channel."""
        sid = str(ctx.guild.id)
        channel = None
        enabled = True
        action = ctx.message.content

        if sid in self.db:
            try:
                channel = ctx.guild.get_channel(int(self.db[sid]["log_channel"]))
            except KeyError:
                channel = None
            try:
                enabled = self.db[sid]["log"]
            except KeyError:
                enabled = False
        else:
            channel = ctx.channel
            enabled = False

        if not enabled:
            return

        if info is None:
            info = "No extra information"

        tag = f"{target.name}#{target.discriminator} ({target.id})"

        embed = Embed(
            title=f"{ctx.author.name}#{ctx.author.discriminator} {ctx.command.name}",
            color=0xFF0000,
        )
        embed.set_thumbnail(url=str(ctx.author.avatar_url))
        embed.add_field(name="Action", value=action, inline=False)
        embed.add_field(name="Target", value=tag)
        embed.add_field(name="Info", value=info)
        embed.set_footer(text=pretty_datetime(datetime.now()))

        await channel.send(embed=embed)
Пример #9
0
    def __init__(self, bot: DiscordBot):
        self.bot = bot
        self.name = "roles"
        self.version = VERSION
        self.backup = True

        db_file = "db/roles.sql"

        try:
            with open("config/config.json") as cfg:
                conf = json.load(cfg)
                self.backup = conf["BackupDB"]
                self.delete_cmds = conf["DeleteCommands"]
        except Exception as error:
            self.bot.log.error(
                f"Error loading prefix from config file.\n    - {error}")

        if os.path.exists(db_file) and self.backup:
            timestamp = pretty_datetime(datetime.now(), display="FILE")
            try:
                shutil.copyfile(db_file, f"db/backups/roles-{timestamp}.sql")
            except IOError as e:
                error_file = f"db/backups/roles-{timestamp}.sql"
                self.bot.log.error(
                    f"Unable to create file {error_file}\n    - {e}")

        self.sql_db = SqliteDict(
            filename=db_file,
            tablename="roles",
            autocommit=True,
            encode=json.dumps,
            decode=json.loads,
        )

        if "servers" not in self.sql_db:
            self.sql_db["servers"] = {}

        self.db = self.sql_db["servers"]
Пример #10
0
    async def info(self, ctx: Context):
        """Show the bot's mission control."""
        embed = Embed(title="Status", color=0x7289DA)

        embed.add_field(name="Time",
                        value=pretty_datetime(datetime.now(), "FULL"))
        embed.add_field(name="Version", value=self.bot.version)

        embed.add_field(name="User",
                        value=f"{self.bot.user} ({self.bot.user.id})",
                        inline=False)

        embed.add_field(name="Plugins",
                        value=f"[{', '.join(self.bot.plugins)}]")
        embed.add_field(name="Servers", value=str(len(self.bot.servers)))

        # Just in case something happened initializing the app info
        if self.bot.app_info is not None:
            embed.set_author(name=self.bot.app_info.name,
                             icon_url=self.bot.app_info.icon_url)

        embed.set_footer(text="https://github.com/CodeBizarre/discord-bot")

        await ctx.send(embed=embed)
Пример #11
0
def test_pretty_datetime_full():
    dt = pretty_datetime(sample)

    assert dt == "2017-8-5 19:0"
Пример #12
0
def test_pretty_datetime_file():
    dt = pretty_datetime(sample, "FILE")

    assert dt == "2017-8-5-19-0"
Пример #13
0
def test_pretty_datetime_time():
    dt = pretty_datetime(sample, "TIME")

    assert dt == "19:0:29"
Пример #14
0
    async def on_message_edit(self, former: Message, latter: Message):
        if former.author.id == self.bot.user.id:
            return

        sid = str(former.guild.id) if former.guild is not None else None

        # Embeds cause message edit events even if the user didn't edit them
        if former.content == latter.content and former.embeds != latter.embeds:
            return

        # Log the edit to the console/log file if enabled
        if self.bot.log_edits:
            timestamp = pretty_datetime(datetime.now(), display="TIME")

            self.bot.log.info(
                f"-{timestamp}- [EDIT] [{former.guild}] #{former.channel}")
            self.bot.log.info(f"[BEFORE] <{former.author}>: {former.content}")
            self.bot.log.info(f"[AFTER] <{latter.author}>: {latter.content}")

        # Process the commands from the message afterwards if enabled
        if self.bot.cmd_on_edit:
            await self.bot.process_commands(latter)

        # If this is a DM, we don't need to try and log to channel or report ghosts
        if sid is not None:
            # Check if the server should report mention deletes
            try:
                report_ghosts = self.bot.servers[sid]["report_ghosts"]
            except KeyError:
                # This server is not configured.
                report_ghosts = False

            if report_ghosts:
                title = f"A message from {former.author.mention} was edited removing"

                difference = [
                    m for m in former.mentions if m not in latter.mentions
                ]
                mentions = [f"{m.name}#{m.discriminator}" for m in difference]

                if difference:
                    await former.channel.send(
                        f"{title} mention(s) from: {mentions}")
                elif former.mention_everyone and not latter.mention_everyone:
                    await former.channel.send(
                        f"{title} an Everyone or Here mention")
                elif former.role_mentions != latter.role_mentions:
                    former.mentions = former.role_mentions - latter.role_mentions
                    mentions = [f"{r.name}" for r in former.mentions]
                    await former.channel.send(
                        f"{title} role mention(s): {mentions}")

            # Log the edit to a channel if the server has it set up
            try:
                if self.bot.servers[sid]["log_edits"]:
                    guild = former.guild
                    channel = guild.get_channel(
                        int(self.bot.servers[sid]["log_channel"]))

                    embed = Embed(title="Message Edited", color=0xFF0000)
                    embed.add_field(
                        name=
                        f"By {former.author.name}#{former.author.discriminator}",
                        value=
                        f"In {former.channel.mention}. UID: {former.author.id}",
                    )
                    embed.add_field(name="Before",
                                    value=former.content,
                                    inline=False)
                    embed.add_field(name="After",
                                    value=latter.content,
                                    inline=False)

                    await channel.send(embed=embed)
            except KeyError:
                pass
Пример #15
0
    async def on_message_delete(self, msg: Message):
        sid = str(msg.guild.id) if msg.guild is not None else None

        # Log the delete to the console/log file if enabled
        if self.bot.log_deletes:
            timestamp = pretty_datetime(datetime.now(), display="TIME")

            header = f"-{timestamp}- [DELETE] "
            content = f"[{msg.guild}] #{msg.channel} <{msg.author}>: {msg.content}"

            self.bot.log.info(f"{header} {content}")

        # If this is a DM, we don't need to try and log to channel or report ghosts
        if sid is not None:
            # Check if the server should report mention deletes
            try:
                report_ghosts = self.bot.servers[sid]["report_ghosts"]
            except KeyError:
                # This server is not configured.
                report_ghosts = False

            if report_ghosts and msg.author.id != self.bot.user.id:
                title = f"A message from {msg.author.mention} was removed mentioning"

                if len(msg.mentions) > 0:
                    mentions = [
                        f"{m.name}#{m.discriminator}" for m in msg.mentions
                    ]
                    await msg.channel.send(f"{title}: {mentions}")
                elif msg.mention_everyone:
                    await msg.channel.send(f"{title}: Everyone or Here")
                elif len(msg.role_mentions) > 0:
                    mentions = [f"{r.name}" for r in msg.role_mentions]
                    await msg.channel.send(f"{title} role: {mentions}")

            # Log the delete to a channel if the server has it set up
            try:
                if self.bot.servers[sid]["log_deletes"]:
                    # Try to get the user who deleted the message, not reliable
                    action = await msg.guild.audit_logs(
                        limit=1,
                        action=AuditLogAction.message_delete).flatten()

                    who = action[0].user

                    guild = msg.guild
                    channel = guild.get_channel(
                        int(self.bot.servers[sid]["log_channel"]))

                    embed = Embed(title="Message Deleted", color=0xFF0000)
                    embed.add_field(
                        name="Last message delete action performed by:",
                        value=f"{who.name}#{who.discriminator} or a bot",
                        inline=False,
                    )
                    embed.add_field(
                        name=
                        f"Author - {msg.author.name}#{msg.author.discriminator}",
                        value=
                        f"From {msg.channel.mention} - UID: {msg.author.id}",
                    )
                    embed.add_field(name="Message",
                                    value=msg.content,
                                    inline=False)

                    await channel.send(embed=embed)
            except KeyError:
                pass