async def roll(self, ctx, *args):
        """Generate a random number based on dice given in D&D style parameters (ex. 1d6)"""
        if len(args) < 1:
            raise UserWarning("You must specify a roll to use this command!")

        try:
            d_index = args[0].lower().index('d')
            qty = int(args[0].lower()[0:d_index])
            faces = int(args[0].lower()[d_index + 1:])
        except ValueError:
            raise UserWarning("Invalid formatting of dice roll!")

        if qty > 50:
            raise UserWarning("Maximum of 50 dice at once.")
        if faces > 10000:
            raise UserWarning("Maximum of 10,000 faces per die.")

        rolls = sample(range(1, faces + 1), qty)

        em = discord.Embed(
            title=f":game_die: Rolling {qty}d{'{:,}'.format(faces)}...",
            description=
            f"{', '.join(['{:,}'.format(i) for i in rolls])}\n\nTotal: {'{:,}'.format(sum(rolls))}",
            color=message_color)
        em.set_footer(text=generate_footer(ctx))
        await ctx.send(embed=em)
    async def block_list_msgrole(self, ctx):
        """List all block_list entries in database."""
        query = session.query(UserSettings)
        to_set = query.filter(
            UserSettings.discord_id == ctx.message.author.id).first()

        if to_set is None:
            raise UserWarning("You have no guilds blocked!")
        else:
            block_list = json.loads(to_set.msgrole_block)
            if not block_list:
                raise UserWarning("You have no guilds blocked!")

        em = discord.Embed(title="Msgrole Block List",
                           description=f"Guilds that you have blocked.",
                           color=message_color)
        em.set_footer(text=generate_footer(ctx))
        for guild_id in block_list:
            guild = self.client.get_guild(guild_id)
            em.add_field(
                # Client can only see names of guilds it's in. Placeholder if it can't find the name.
                name=f"{guild if guild else 'No longer in this guild.'}",
                value=f"`ID`: {guild_id}")

        await ctx.send(embed=em)
async def on_command_error(ctx, error):
    """Error handler, parses how message author should be notified about an error."""
    try:
        # If CommandNotFound, fail silently
        if isinstance(error, discord.ext.commands.CommandNotFound):
            return

        # error.__cause__ finds cause of CommandInvokeError, useful if exception thrown from inside command.
        if isinstance(error.__cause__, UserWarning):
            title = "There was a user warning while running the command!"
            # Generate formatted string
            exc = f"{type(error.__cause__).__name__}: {error.__cause__}"
        else:
            title = "There was an error while running the command!"
            # Generate formatted string
            exc = f"{type(error).__name__}: {error}"

        em = discord.Embed(title=title,
                           description=f"`{exc}`",
                           color=error_color)
        em.set_footer(text=generate_footer(ctx))
        await ctx.send(embed=em)
    except Exception as error:
        # If there is an issue with sending a message to the error channel, just ignore it.
        pass
    async def hello_world(self, ctx):
        """Respond with an embedded response."""
        em = discord.Embed(title="Response",
                           description="Hello world!",
                           color=message_color)
        em.set_footer(text=generate_footer(ctx))

        await ctx.send(embed=em)
Exemple #5
0
    async def user_count(self, ctx):
        """Counts the number of unique users the bot is connected to."""
        em = discord.Embed(
            title="User Count",
            description=f"I can see a total of {len(ctx.bot.users):,} users!",
            color=message_color)
        em.set_footer(text=generate_footer(ctx))

        await ctx.send(embed=em)
 async def epoch_time(self, ctx):
     """Get the system time and post it as Unix time."""
     em = discord.Embed(
         title=":clock1130: Current Epoch Time",
         description=
         f"{time.time():,.2f}s\n\n[What?](https://en.wikipedia.org/wiki/Unix_time)",
         color=message_color)
     em.set_footer(text=generate_footer(ctx))
     await ctx.send(embed=em)
Exemple #7
0
    async def ping_bot(self, ctx):
        """Basic call and response command"""
        em = discord.Embed(
            title="Pong!",
            description="Hello! Everything seems to be operational.",
            color=message_color)
        em.set_footer(text=generate_footer(ctx))

        await ctx.send(embed=em)
    async def message_role(self, ctx, *args):
        # Check if there's a mentioned role. If not, string match.
        if len(ctx.message.role_mentions) < 1:
            found_role = await find_by_name(args[0], ctx.message.guild.roles)
            if found_role is None:
                raise UserWarning("You must mention one role.")
        else:
            found_role = ctx.message.role_mentions[0]

        # If the set role has no members, throw error.
        if len(found_role.members) == 0:
            raise UserWarning("That role has no members!")

        em = discord.Embed(
            title=":mega: Sending messages...",
            description=f"Sending requested messages to {found_role.mention}",
            color=message_color)
        em.set_footer(text=generate_footer(ctx))

        # Send message to all users in selected role.
        for member in found_role.members:
            try:
                # Query database to get member preferences.
                query = session.query(UserSettings)
                block_pref = query.filter(
                    UserSettings.discord_id == member.id).first()

                # Ensure query returned something.
                if block_pref is not None:
                    # Check that their blocklist is populated.
                    if isinstance(block_pref.msgrole_block, str):
                        # Check if guild id is in blocklist.
                        if ctx.guild.id in json.loads(
                                block_pref.msgrole_block):
                            # If so, raise exception.
                            raise UserWarning("This user has blocked msgrole.")

                # Send embedded msgrole.
                em_sent = discord.Embed(
                    title=f"Role message from {ctx.message.author.name}",
                    description=generate_clean_msgrole(ctx, args),
                    color=message_color)
                em_sent.set_footer(
                    text=f"Sent from: {ctx.guild.name}\n"
                    f"Use f.block {ctx.guild.id} if you no longer wish to receive messages from this guild."
                )
                em_sent.set_author(name=ctx.guild.name,
                                   icon_url=ctx.guild.icon_url)
                await member.send(embed=em_sent)
            except Exception as e:
                # If sending dm failed, add entry to list.
                em.add_field(name=f"Failed to send message to {member.name}",
                             value=f"`{type(e).__name__}: {e}`")
                pass
        # Send success/fail list back to guild.
        await ctx.send(embed=em)
    async def report_bug(self, ctx):
        """Gives the user information on how to report bugs they find."""
        em = discord.Embed(
            title="Found a bug? :bee:",
            description="You can report bugs on the "
            "[Fox Utilities issues](https://github.com/FevenKitsune/Fox-Utilities/issues) page on GitHub!",
            color=message_color)
        em.set_footer(text=generate_footer(ctx))

        await ctx.send(embed=em)
Exemple #10
0
    async def invite_bot(self, ctx):
        """Sends information on the development server, the GitHub, and the invite link."""
        em = discord.Embed(title="Invite me!",
                           description=f"[Invite link!]({bot_invite})\n"
                           f"[Development server!]({bot_development_server})\n"
                           f"[GitHub!]({bot_source})",
                           color=message_color)
        em.set_footer(text=generate_footer(ctx))

        await ctx.send(embed=em)
Exemple #11
0
    async def server_count(self, ctx):
        """Counts the number of servers the bot is connected to."""
        em = discord.Embed(
            title="Server Count",
            description=
            f"I am currently connected to {len(self.client.guilds):,} servers.",
            color=message_color)
        em.set_footer(text=generate_footer(ctx))

        await ctx.send(embed=em)
    async def tags(self, ctx):
        """Gives the user information on permission tags, which allow non-admins to access admin commands."""
        em = discord.Embed(
            title="Fox Utilities Permission Tags",
            description=
            "Create a role with the syntax `fox:name_of_command` to give them "
            "permission to access that command! Will work with any admin command!",
            color=message_color)
        em.set_footer(text=generate_footer(ctx))

        await ctx.send(embed=em)
    async def reload(self, ctx, *args):
        """Unload all discord.py cogs and load them back. Easier than a full reboot."""
        em = discord.Embed(
            title="System Reload",
            color=message_color
        )
        em.set_footer(text=generate_footer(ctx))

        # Stores which cogs passed and which cogs failed.
        success = []
        failed = []

        # Check for extensions first.
        if len(extensions) == 0:
            em.add_field(
                name="Oh well.",
                value="Doesn't look like there are any extensions defined.")
            await ctx.send(embed=em)
            return
        for extension in extensions:
            try:
                # Unload extension
                self.client.unload_extension(extension)
            # Continue if unload failed.
            except Exception as e:
                pass
        for extension in extensions:
            try:
                # Load extension
                self.client.load_extension(extension)
            except Exception as e:
                # Post error to embed if load failed.
                expt = f"{type(e).__name__}: {e}"
                failed.append([extension, expt])
            else:
                # Post to embed if load succeeded.
                success.append(extension)

        em.add_field(
            name=":white_check_mark: Load Passed:",
            value='\n'.join([
                f"`{i}: PASS`" for i in success
            ]) if success else "`None`"
        )

        em.add_field(
            name=":warning: Load Failed:",
            value='\n'.join([
                f"`{i[0]}: {i[1]}`" for i in failed
            ]) if failed else "`None`"
        )
        await ctx.send(embed=em)
    async def git_pull(self, ctx):
        """Pulls the latest version of the bot from Git"""
        # Find Git repository the bot is stored in
        repo = git.Repo(os.getcwd(), search_parent_directories=True)

        # Run git pull and post results into embed.
        em = discord.Embed(
            title="Fox Utilities GitHub",
            description=f"```smalltalk\n{str(repo.git.pull())}\n```",
            color=message_color
        )
        em.set_footer(text=generate_footer(ctx))
        await ctx.send(embed=em)
    async def sys_uptime(self, ctx):
        """Get system uptime from container."""
        # Read system uptime.
        with open("/proc/uptime", "r") as proc_ut:
            ut = float(proc_ut.readline().split()[0])

        em = discord.Embed(
            title="Container Uptime",
            description=
            f"/proc/uptime: {str(datetime.timedelta(seconds=int(ut)))}",
            color=message_color)
        em.set_footer(text=generate_footer(ctx))

        await ctx.send(embed=em)
    async def block_msgrole(self, ctx, args):
        """Push block settings to database."""
        query = session.query(UserSettings)
        to_set = query.filter(
            UserSettings.discord_id == ctx.message.author.id).first()

        # Check that a valid ID was passed.
        try:
            int(args)
        except ValueError:
            raise UserWarning("ID given was not a valid ID.")

        if len(args) != 18:
            raise UserWarning("ID given is the incorrect length.")

        # If user is not in database, create new entry.
        if to_set is None:
            to_set = UserSettings(discord_id=ctx.message.author.id,
                                  msgrole_block=json.dumps([int(args)]))
            session.add(to_set)
            # Load block_list for posting in msg
            block_list = json.loads(to_set.msgrole_block)
        else:
            # Load in block_list and append requested guild.
            block_list = json.loads(to_set.msgrole_block)
            if int(args) in block_list:
                raise UserWarning("This guild is already blocked!")
            block_list.append(int(args))
            to_set.msgrole_block = json.dumps(block_list)

        session.commit()

        em = discord.Embed(
            title="Msgrole Blocked",
            description=f"You have successfully blocked ID {args}",
            color=message_color)
        em.set_footer(text=generate_footer(ctx))

        # Add fields for all guild's blocked.
        for guild_id in block_list:
            guild = self.client.get_guild(guild_id)
            em.add_field(
                name=f"{guild if guild else 'No longer in this guild.'}",
                value=f"`ID`: {guild_id}")

        await ctx.send(embed=em)
    async def sniped(self, ctx):
        """Retrieves the last mention within a given channel, even if that mention was deleted."""
        em = discord.Embed(color=message_color)
        em.set_footer(text=generate_footer(ctx))

        try:
            grabbed_message = snipe_db[f"{ctx.author.id}"][f"{ctx.channel.id}"]
        except Exception:
            em.add_field(
                name=f"I don't see the last mention...",
                value=f"Mentions are stored for a limited period of time!"
            )
        else:
            em.add_field(
                name=f"I found something:",
                value=f"Mentioned by: <@{grabbed_message['author_id']}>\n\n{grabbed_message['content']}"
            )

        await ctx.send(embed=em)
    async def purge_block_msgrole(self, ctx):
        """Delete all block_list entries from database."""
        query = session.query(UserSettings)
        to_set = query.filter(
            UserSettings.discord_id == ctx.message.author.id).first()

        if to_set is None:
            raise UserWarning("You have no guilds blocked!")
        else:
            to_set.msgrole_block = json.dumps([])

        session.commit()

        em = discord.Embed(
            title="Msgrole Purged",
            description=f"You have successfully erased your block list.",
            color=message_color)
        em.set_footer(text=generate_footer(ctx))

        await ctx.send(embed=em)
    async def reboot(self, ctx):
        """Restart the bot on the system level."""
        em = discord.Embed(
            title="Rebooting the bot!",
            description="Please wait while the bot reboots...",
            color=message_color
        )
        em.set_footer(text=generate_footer(ctx))
        await ctx.send(embed=em)

        # Get bot process
        p = psutil.Process(os.getpid())
        for handler in p.open_files() + p.connections():
            # Close all active connections and processes
            os.close(handler.fd)

        # Get python exec
        python = sys.executable
        # Start python process
        os.execl(python, python, *sys.argv)
    async def help(self, ctx):
        """Help menu. Processes the list of available commands into a readable menu."""
        em = discord.Embed(title="Fox Utilities Help Guide",
                           description=bot_description,
                           color=message_color)
        em.set_footer(text=generate_footer(ctx))

        for cmd in sorted(self.client.commands,
                          key=lambda command: command.cog_name):
            # If not developer, do not show hidden commands.
            if cmd.hidden and not (ctx.author.id == developer_id):
                pass
            else:
                # Help field formatter.
                em.add_field(
                    name=
                    f"{'#' if cmd.hidden else ''}`{cmd.cog_name}`> {cmd.name} {cmd.usage}",
                    value=cmd.brief,
                    inline=False)

        await ctx.author.send(embed=em)
    async def invites(self, ctx):
        """Get a list of invite codes and the number of uses for a given user."""
        # If no one was mentioned, assume author is target.
        if ctx.message.mentions:
            user = ctx.message.mentions[0]
        else:
            user = ctx.message.author

        em = discord.Embed(title="**{}\'s Invites**".format(user.name),
                           color=message_color)
        em.set_footer(text=generate_footer(ctx))

        # Iterate through the guild invites and parse invites by the targeted user.
        for inv in await ctx.message.guild.invites():
            if inv.inviter == user:
                time_formatter = "%b %-d, %Y at %-l:%M%p"
                em.add_field(
                    name="Invite code: ####{}".format(str(inv.code)[4:]),
                    value=
                    f"Uses: {inv.uses}\nCreated at: {inv.created_at.strftime(time_formatter)}"
                )

        await ctx.send(embed=em)
Exemple #22
0
    async def privacy_information(self, ctx):
        """Sends information on what data this bot collects and how we use it."""
        em = discord.Embed(
            title="Privacy Information",
            description=
            "Privacy is important to everyone, so this is a quick overview of the data we have stored.",
            color=message_color)
        em.set_footer(text=generate_footer(ctx))

        # Command
        em.add_field(
            name="Error Logging",
            value=
            "If a command returns an error, the contents of the command will be logged for debugging purposes. "
            "Neither the name of the sender nor the name of the server will be logged."
        )

        em.add_field(
            name="Data Persistence",
            value=
            "Snipe tool data: the contents of your last mention is stored in "
            "memory, meaning it is wiped as soon as the bot stops running.\n"
            "User preferences: the user ID and guild ID (where applicable) is stored in a local database."
        )

        em.add_field(
            name="Misuse Policy",
            value=
            "We do not, nor will we ever use the bot to access information not specified by this privacy notice."
        )

        em.add_field(
            name="Questions?",
            value="Feel free to ask questions in the Development Server!")

        await ctx.author.send(embed=em)