Example #1
0
    async def register(self, ctx, member: discord.Member=None):
        """ Register for betting.

        :member: empty discord.Member object
        """

        member = ctx.message.author
        member_id = ctx.message.author.id
        display_name = ctx.message.author.name
        server_id = ctx.message.server.id

        # Load some config settings
        channel_id = ConfigLoader().load_server_int_setting(
            server_id,
            'BettingGame',
            'bet_channel_id'
        )

        plugin_enabled = ConfigLoader().load_server_boolean_setting(
            server_id,
            'BettingGame',
            'enabled'
        )

        # Have to cast ctx.message.channel and ctx.message.server to strings
        if (member is not None
                and int(ctx.message.channel.id) == channel_id
                and plugin_enabled
           ):
            row = DatabaseHandler().fetch_results(
                "SELECT 1 FROM credit_bet WHERE userID = {0} \
                and serverID = {1}".format(str(member_id), str(server_id))
            )
            if row is None:
                query = """
                        INSERT INTO credit_bet (serverID, username, userID, \
                        displayName, credits, dateJoined, timesBet, lastClaimTime) \
                        VALUES (?, ?, ?, ?, ?, ?, ?, ?)
                        """
                DatabaseHandler().insert_into_database(
                    query,
                    (
                        str(server_id),
                        str(member),
                        member_id,
                        display_name,
                        500,
                        str(datetime.now()),
                        0,
                        str(datetime.now())
                    )
                )
                await self.bot.say(
                    "{0.mention}, you are now registered! {1}bet to play! " \
                    "Goodluck!".format(member, self.prefix))
            else:
                await self.bot.say(
                    "{0.mention}: you're already registered. Please do {1}bet " \
                    "to play!".format(member, self.prefix))
Example #2
0
    async def scores(self, ctx, member: discord.Member=None):
        """Display the top 5 with > 0 points.

        :member: empty discord.Member object
        """
        member = ctx.message.author
        server_id = ctx.message.server.id

        channel_id = ConfigLoader().load_server_int_setting(
            server_id,
            'BettingGame',
            'bet_channel_id'
        )

        plugin_enabled = ConfigLoader().load_server_boolean_setting(
            server_id,
            'BettingGame',
            'enabled'
        )
        if (
                member is not None
                and int(ctx.message.channel.id) == channel_id
                and plugin_enabled
        ):
            output_string = ''

            row = DatabaseHandler().fetch_all_results(
                "SELECT displayName, credits, timesBet \
                FROM credit_bet WHERE serverID = {0} AND credits > 0 \
                ORDER BY credits DESC LIMIT 5"
                .format(str(server_id))
            )
            if len(row) > 0:
                names = {d[0] for d in row}
                max_name_len = max(map(len, names))
                max_name_len = 22 if max_name_len > 22 else max_name_len
                spacer = max_name_len + 4
                output_string = '```{0: <{1}}  Credits\n'.format('User', spacer)
                output_string = output_string + '{0: <{1}}  -------\n'.format('----', spacer)

                for item in enumerate(row):
                    # Add the name and credit amounts of the top 5 users.
                    # Truncate usernames at 22 spaces and add '..'
                    output_string = output_string + "{0: <{1}}  {2}\n".format(
                        item[1][0][:22] + '..' if len(item[1][0]) > 22 else item[1][0],
                        spacer,
                        item[1][1]
                    )
                output_string = output_string + "\n```"
                return await self.bot.say(output_string)
            else:
                return await self.bot.say("There are no users currently in the lotto, or " \
                                          "all participating users have 0 credits.")
Example #3
0
    async def welcome_user(self, server_id: str, member: str, server: str):
        """
        Send a message to a configured channel when a user joins the server.

        :param server_id: the discord server snowflake ID
        :param member: the discord member snowflake ID
        :param server: the discord server that triggered this
        :return:

        @TODO: can probably reduce arguments and just pass the server argument, and from this grab the server.id
        """
        welcome_enabled = ConfigLoader().load_server_boolean_setting(
            server_id,
            'JoinPart',
            'member_join_enabled'
        )

        if welcome_enabled:
            welcome_channel = ConfigLoader().load_server_config_setting(
                server_id,
                'JoinPart',
                'welcome_channel_id'
            )

            welcome_message = ConfigLoader().load_server_string_setting(
                server_id,
                'JoinPart',
                'welcome_message'
            )

            emote_array = []
            for emoji in member.server.emojis:
                emote_array.append(emoji)

            if not emote_array:
                await self.bot.send_message(
                    discord.Object(id=welcome_channel),
                    welcome_message
                    .replace("{server}", server.name)
                    .replace("{user}", member.mention)
                    .replace("{emote}", ''))
            else:
                await self.bot.send_message(
                    discord.Object(id=welcome_channel),
                    welcome_message
                    .replace("{server}", server.name)
                    .replace("{user}", member.mention)
                    .replace("{emote}", str(random.choice(emote_array))))
        return
Example #4
0
    def get_tos_channel_valid(server_id):
        """
        Check if the server has specified a specific channel to display the message informing a user that they
        must accept the Terms of Service before they can use certain commands.

        :param server_id: the discord server snowflake ID
        :return: True if channel specified, False if not
        """
        try:
            try:
                ConfigLoader().load_server_int_setting(
                    server_id,
                    'ConfigSettings',
                    'not_accepted_channel_id'
                )
                return True
            except ValueError:
                # ErrorLogging().log_error_without_await(
                #     traceback.format_exc(),
                #     'BotResources: get_tos_channel_id (inner)'
                # )
                return False
        except ValueError:
            # ErrorLogging().log_error_without_await(
            #     traceback.format_exc(),
            #     'BotResources: get_tos_channel_id (outer)'
            # )
            return False
Example #5
0
    async def generate_config(self, ctx):
        """
        Checks if the member is the server or the
        bot owner and if so runs the generate_config function
        from the general_bot_resources

        :param ctx: discord.py Context
        """
        member_id = ctx.message.author.id

        if member_id == ctx.message.server.owner_id or \
                int(member_id) == ConfigLoader().load_config_setting_int('BotSettings', 'owner_id'):
            file_exists = await ConfigLoader(self.bot).check_if_config_exists(
                ctx.message.server.id
            )

            if not file_exists:
                await ConfigLoader(self.bot).generate_default_config_file(
                    ctx.message.server.id,
                    member_id
                )
            else:
                await self.bot.say("Configuration file already exists.")
        else:
            return
Example #6
0
    async def balance(self, ctx, member: discord.Member=None):
        """ Get user balance.

        :member: empty discord.Member object
        """
        member = ctx.message.author
        member_id = ctx.message.author.id
        server_id = ctx.message.server.id

        # Load some config settings
        channel_id = ConfigLoader().load_server_int_setting(
            server_id,
            'BettingGame',
            'bet_channel_id'
        )

        plugin_enabled = ConfigLoader().load_server_boolean_setting(
            server_id,
            'BettingGame',
            'enabled'
        )

        # Have to cast ctx.message.channel and ctx.message.server to strings
        if member is not None and int(ctx.message.channel.id) == channel_id and plugin_enabled:
            row = DatabaseHandler().fetch_results(
                "SELECT 1 FROM credit_bet WHERE userID = {0} \
                and serverID = {1}".format(str(member_id), str(server_id))
            )
            #print("Row: {}".format(row))
            if row is None:
                return await self.bot.say(
                    "{0.mention}: please do {1}register to " \
                    "join the lotto.".format(member, self.prefix))
            else:
                remaining_credits = DatabaseHandler().fetch_results(
                    "SELECT credits FROM credit_bet \
                    WHERE userID = {0} AND serverID = {1}".format(
                        str(member_id),
                        str(server_id)
                    )
                )
                await self.bot.say(
                    "{0.mention}: your balance is {1}.".format(
                        member,
                        remaining_credits[0]
                    )
                )
Example #7
0
    async def logout(self, ctx):
        """
        This function is designed to logout the bot out depending on the environment in use.  It still makes use of
        the logout functionality built right into discord.py, but with an extra step if using a linux environment.

        It is important to note that the systemd_logout functionality won't work if the user/group the bot is running
        under requires authentication to run the following: systemctl stop SERVICENAME

        Please keep that in mind.

        :param ctx: discord.py Context
        :return:
        """
        user_id = ctx.message.author.id

        # Try to run systemd_logout, and if that fails run the normal logout method
        # The issue here is if they are using systemd but pass in the wrong service name it'll just reboot
        # after logging out - not really our problem though, they should correct that in the bot config and try again
        # We should probably raise more acceptable errors than TypeError (but still keep that one)
        if int(user_id) == self.owner_id:
            await self.bot.say("Shutting down, bye!")
            try:
                if self.get_system_environment():
                    systemd_enabled = ConfigLoader(
                    ).load_config_setting_boolean('BotSettings',
                                                  'systemd_enabled')

                    if systemd_enabled:
                        # so even if the bot logs out, if the systemd_logout fails the bot is going to come back online
                        # assuming they have the service set to do so
                        systemd_name = ConfigLoader(
                        ).load_config_setting_string('BotSettings',
                                                     'systemd_name')
                        await self.bot.logout()
                        await self.systemd_logout(systemd_name)
                    else:
                        raise TypeError
                else:
                    raise TypeError
            except TypeError:
                print(
                    "SHUTDOWN: non-linux environment, systemd not enabled, or something failed."
                )
                await self.bot.logout()
        return
Example #8
0
    def __init__(self, bot):
        self.bot = bot
        self.prefix = ConfigLoader().load_config_setting('BotSettings', 'command_prefix')

        self.total_seconds = 0
        self.total_hours = 0
        self.used_secs = 0
        self.seconds_left = 0
        self.final_minutes = 0
Example #9
0
    async def goodbye_user(self, server_id: str, member: str):
        """
        Send a message to a configured channel when a user leaves (or is kicked) from the server.

        :param server_id: the discord server snowflake ID
        :param member: the discord member snowflake ID
        :param server: the discord server that triggered this
        :return:

        @TODO: can probably reduce arguments and just pass the server argument, and from this grab the server.id
        """
        part_enabled = ConfigLoader().load_server_boolean_setting(
            server_id,
            'JoinPart',
            'member_part_enabled'
        )

        if part_enabled:
            part_channel = ConfigLoader().load_server_config_setting(
                server_id,
                'JoinPart',
                'leave_channel_id'
            )

            part_message = ConfigLoader().load_server_string_setting(
                server_id,
                'JoinPart',
                'part_message'
            )
            display_name = member.display_name

            await self.bot.send_message(
                discord.Object(id=part_channel),
                part_message
                .replace("{name}", str(member))
                .replace("{display_name}", display_name)
            )
        return
Example #10
0
    async def reset_lotto_entries(self, ctx, member: discord.Member=None):
        """Reset the lotto entries for the server where
        where the commands is being used.

        :member: empty discord.Member object
        """
        member = ctx.message.author
        member_id = ctx.message.author.id
        server_id = ctx.message.server.id

        bot_admin_users = []
        bot_admin_roles = []
        user_roles_list = []

        for user_role in ctx.message.author.roles:
            user_roles_list.append(str(int(user_role.id)))

        try:
            bot_admins_user_list = ConfigLoader().load_server_string_setting(
                ctx.message.server.id,
                'BotAdmins',
                'bot_admin_users'
            )

            bot_admins_role_list = ConfigLoader().load_server_string_setting(
                ctx.message.server.id,
                'BotAdmins',
                'bot_admin_roles'
            )

            for user in bot_admins_user_list.split():
                bot_admin_users.append(user)

            for role in bot_admins_role_list.split():
                bot_admin_roles.append(role)
        except (configparser.NoSectionError, configparser.Error):
            pass

        try:
            if member_id == ctx.message.server.owner_id or \
            int(member_id) == ConfigLoader().load_config_setting_int(
                        'BotSettings', 'owner_id'
            ) or \
            str(member_id) in bot_admin_users or \
            [admin_role for admin_role in user_roles_list if admin_role in bot_admin_roles]:
                args = (str(server_id),)
                DatabaseHandler().update_database_with_args(
                    "DELETE FROM credit_bet WHERE serverID = ?",
                    args
                )
                return await self.bot.say("{0.mention}: lottery table for this server reset.".format(member))
        except configparser.Error as config_error:
            print("Error with resetlotto command.")
Example #11
0
    async def change_username(self, ctx, username: str):
        """
        Change the bot username.
        """
        member_id = ctx.message.author.id

        if (member_id == ctx.message.server.owner_id
                or int(member_id) == ConfigLoader().load_config_setting_int(
                    'BotSettings',
                    'owner_id'
                )
           ):
            await self.bot.change_nickname(ctx.message.server.me, username)
            return await self.bot.say("Changed my username!")
Example #12
0
def main():
    """
    Run...run everything.  Seriously, I didn't feel this part of the code really needed legitimate documentation.
    It's called main(), that should be obvious as to what it does.

    But, just in case:
        - Load all of the extensions, and inform user if any failed to load
        - Removes the `help` command as we don't use that in this bot for any reason
        - Actually start up the bot

    Raises:
        - AttributeError
        - TypeError
        - discord.LoginFailure (SystemExit)
    """
    print('Preparing...')

    # Create some needed directories, just in case they don't already exist as needed.
    ErrorLogging().create_directory()
    ConfigLoader().create_directory()

    try:
        startup_extensions = []
        for plugin in EXTENSIONS.split():
            startup_extensions.append(plugin)

        # We don't have a help command that is of valid use, so let's just disable it completely to make everything
        # that much easier.
        CLIENT.remove_command("help")

        for extension in startup_extensions:
            try:
                CLIENT.load_extension(extension)
            except (ValueError, AttributeError, TypeError, ImportError) as err:
                exc = '{}: {}'.format(type(err).__name__, err)
                print('Failed to load extension {}\n{}\n'.format(extension, exc))
        CLIENT.run(BOT_TOKEN)
    except AttributeError:
        CLIENT.logout()
        raise AttributeError
    except TypeError:
        CLIENT.logout()
        raise TypeError
    except discord.LoginFailure as login_error:
        print("There was an issue with logging in:\n{0}\n".format(login_error))
        raise SystemExit
    async def update_channel_list(self,
                                  ctx,
                                  add_or_remove: str,
                                  channel_id: str,
                                  member: discord.Member = None):
        """
        Update the configured channel list to add or remove a channel where the guild command can be used.
        Command is executed via the `rolechannel` command.

        Examples:
            > rolechannel add 1234567890
            Configuration file updated.

            > rolechannel add 1234567890
            Role already added.

            > rolechannel test 1234567890
            Please specify if I am adding or removing a channel.

            > rolechannel remove 1234567890
            Configuration file updated.

        :param ctx: discord.py Context
        :param add_or_remove: (str) [add, remove] passed in string to determine if a channel is being added or removed
        :param channel_id: discord snowflake ID for the channel, requires the direct ID and cannot be added via pinging
        :param member: optional discord.Member object
        :return:
        """
        member = ctx.message.author
        server_id = str(ctx.message.server.id)

        if member is not None:
            if add_or_remove != 'add' and add_or_remove != 'remove':
                return await self.bot.say(
                    "Please specify if I am adding or removing a channel.")

            current_channel_list = ConfigLoader().load_server_config_setting(
                server_id, 'RoleAssignment', 'assignment_channel_id')

            if add_or_remove == 'add':
                if not BotResources().contains_word(current_channel_list,
                                                    channel_id):
                    if current_channel_list == 'NOT_SET':
                        updated_channel_list = channel_id
                    else:
                        updated_channel_list = current_channel_list + " " + channel_id
                else:
                    return await self.bot.say("Channel already added.")

                if add_or_remove == 'remove':
                    if BotResources().contains_word(current_channel_list,
                                                    channel_id):
                        updated_channel_list = current_channel_list.strip(
                            ' ' + channel_id + ' ')

                if updated_channel_list.isspace() or len(
                        updated_channel_list) == 0:
                    updated_channel_list = 'NOT_SET'

                filename = ctx.message.server.id
                await ConfigCommands(self.bot).update_config_file(
                    filename, 'RoleAssignment', 'assignment_channel_id',
                    updated_channel_list.strip(), ctx.message)
Example #14
0
    async def get_config_information(self, ctx, member: discord.Member=None):
        """Get the server configuration settings and send in a private message

        :param ctx: discord.py Context
        :param member: empty discord.Member object
        :return:
        """
        member = ctx.message.author
        member_id = ctx.message.author.id
        server_id = ctx.message.server.id

        bot_admin_users = []
        bot_admin_roles = []
        user_roles_list = []

        for user_role in ctx.message.author.roles:
            user_roles_list.append(str(int(user_role.id)))

        try:
            bot_admins_user_list = ConfigLoader().load_server_string_setting(
                ctx.message.server.id,
                'BotAdmins',
                'bot_admin_users'
            )

            bot_admins_role_list = ConfigLoader().load_server_string_setting(
                ctx.message.server.id,
                'BotAdmins',
                'bot_admin_roles'
            )

            for user in bot_admins_user_list.split():
                bot_admin_users.append(user)

            for role in bot_admins_role_list.split():
                bot_admin_roles.append(role)

        except (configparser.NoSectionError, configparser.Error):
            pass

        try:
            if member_id == ctx.message.server.owner_id or \
                int(member_id) == ConfigLoader().load_config_setting_int(
                      'BotSettings', 'owner_id'
                ) or \
                str(member_id) in bot_admin_users or \
                    [admin_role for admin_role in user_roles_list if admin_role in bot_admin_roles]:
                return_string = "```Settings for {0}:\n\n".format(ctx.message.server.name)

                parser = configparser.ConfigParser()
                loaded_file = BotResources().load_config(
                    '%s.ini' % (
                        os.path.join(
                            self.server_settings_path,
                            str(server_id)
                        )
                    ),
                )
                parser.read(loaded_file)

                for section in parser.sections():
                    return_string = return_string + section + ":\n"
                    for name, value in parser.items(section):
                        return_string = return_string + "{0}: {1}".format(name, value) + "\n"
                        return_string = return_string + "\n"

                return_string = return_string + "```"

                await self.bot.send_message(member, return_string)
                return await self.bot.delete_message(ctx.message)
        except discord.Forbidden:
            print("There was a discord.Forbidden error.")
            bot_message = await self.bot.say(
                "I am unable to message you. You may have me blocked, "
                "or personal messages disabled."
            )
            await asyncio.sleep(5)
            await self.bot.delete_message(ctx.message)
            return await self.bot.delete_message(bot_message)
        except configparser.Error as config_error:
            print("Error with the configuration file: \n{0}".format(config_error))
Example #15
0
 def __init__(self):
     self.prefix = ConfigLoader().load_config_setting('BotSettings', 'command_prefix')
Example #16
0
    async def bet(self, ctx, amount: int, member: discord.Member=None):
        """ Let's bet.

        :amount: the amount the user has decided to bet
        :member: empty discord.Member object
        """
        member = ctx.message.author
        member_id = ctx.message.author.id
        server_id = ctx.message.server.id

        # Load some config settings
        channel_id = ConfigLoader().load_server_int_setting(
            server_id,
            'BettingGame',
            'bet_channel_id'
        )

        # if this fails it's not a boolean so we'll fix that but disable the plugin
        plugin_enabled = ConfigLoader().load_server_boolean_setting(
            server_id,
            'BettingGame',
            'enabled'
        )

        minimum_bet = ConfigLoader().load_server_int_setting(
            server_id,
            'BettingGame',
            'minimum_bet'
        )

        if (
                isinstance(amount, int)
                and plugin_enabled
                and int(ctx.message.channel.id) == channel_id
        ):
            # Have to cast ctx.message.channel.id and ctx.message.server.id to ints
            if member is not None and amount >= minimum_bet:
                row = DatabaseHandler().fetch_results(
                    "SELECT 1 FROM credit_bet WHERE userID = {0} and serverID = {1}".format(
                        str(member_id),
                        str(server_id)
                    )
                )
                if row is None:
                    return await self.bot.say(
                        "{0.mention}: please do {1}register to join the lotto.".format(
                            member,
                            self.prefix
                        )
                    )
                else:
                    remaining_credits = DatabaseHandler().fetch_results(
                        "SELECT credits FROM credit_bet WHERE userID = {0} AND \
                        serverID = {1}".format(
                            str(member_id),
                            str(server_id)
                        )
                    )
                    if remaining_credits[0] < amount:
                        return await self.bot.say(
                            "Insufficient credits ({0})".format(
                                remaining_credits[0]
                            )
                        )
                    else:
                        bot_number = random.randint(1, 100)
                        user_number = random.randint(1, 100)
                        if bot_number > user_number:
                            new_balance = remaining_credits[0] - amount
                            DatabaseHandler().update_database(
                                "UPDATE credit_bet SET credits = {0} WHERE userID = {1} \
                                AND serverID = {2}".format(
                                    new_balance,
                                    str(member_id),
                                    str(server_id)
                                )
                            )
                            await self.bot.say(
                                "Sorry, {0.mention}, you lost with a roll of {1} " \
                                "against {2}! Your balance is now {3}!"
                                .format(member, user_number, bot_number, new_balance)
                            )
                        elif user_number > bot_number:
                            new_balance = remaining_credits[0] + amount
                            DatabaseHandler().update_database(
                                "UPDATE credit_bet SET credits = {0} \
                                WHERE userID = {1} AND serverID = {2}"
                                .format(new_balance, str(member_id), str(server_id))
                            )
                            await self.bot.say(
                                "Congratulations, {0.mention}, you won with a roll " \
                                "of {1} against {2}! Your balance is now {3}!"
                                .format(member, user_number, bot_number, new_balance)
                            )
                        else:
                            await self.bot.say(
                                "It was a tie, {0.mention}, with a roll of {1}! " \
                                "Your balance remains {2}!".format(
                                    member,
                                    user_number,
                                    remaining_credits[0]
                                )
                            )
            else:
                await self.bot.say("The minimum bet is {0}".format(minimum_bet))
        return
Example #17
0
    async def helpme(self, ctx):
        """Free credits for those that qualify.

        By default, this will check against a 24 hour timer to determinme
        if the user is eligable to use the command again.

        @TODO: allow owners to enable setting so that the 24 hour timer
               only begins after the user has run out of credits
        """
        member_id = ctx.message.author.id
        member = ctx.message.author
        server_id = ctx.message.server.id

        # Load some config settings
        channel_id = ConfigLoader().load_server_int_setting(
            server_id,
            'BettingGame',
            'bet_channel_id'
        )

        # Grab the time between helpme users as set by the server
        helpme_timer = ConfigLoader().load_server_int_setting(
            server_id,
            'BettingGame',
            'helpme_cooldown'
        )

        # Grab the minimum credits for using helpme
        minimum_credits = ConfigLoader().load_server_int_setting(
            server_id,
            'BettingGame',
            'helpme_minimum'
        )

        # Grab how many credits they get when using helpme
        helpme_bonus = ConfigLoader().load_server_int_setting(
            server_id,
            'BettingGame',
            'helpme_bonus'
        )

        # check if the plugin enabled; if bad value, the function inside
        # of main will handle catching that
        plugin_enabled = ConfigLoader().load_server_boolean_setting(
            server_id,
            'BettingGame',
            'enabled'
        )

        if plugin_enabled and int(ctx.message.channel.id) == channel_id:
            information = DatabaseHandler().fetch_all_results(
                'SELECT credits, lastClaimTime AS \
                "[timestamp]" FROM credit_bet WHERE \
                userID = {0} AND serverID = {1}'.format(
                    str(member_id),
                    str(server_id))
            )
            current_date = datetime.now()
            member_credits = information[0][0]
            last_used_time = information[0][1]
            if member_credits >= minimum_credits:
                return await self.bot.say(
                    "{0.mention}, you are above the minimum amount {1}; you " \
                    "cannot use this command (balance of {2}).".format(
                        member,
                        minimum_credits,
                        member_credits
                    )
                )
            else:
                if last_used_time is not None:
                    self.total_seconds = (current_date - last_used_time).total_seconds()
                if int(self.total_seconds) >= helpme_timer:
                    self.total_seconds = int(helpme_timer - self.total_seconds)
                    self.total_hours = int(self.total_seconds / 3600)
                    self.used_secs = int(self.total_hours * 3600)
                    self.seconds_left = int(self.total_seconds - self.used_secs)
                    self.final_minutes = int(self.seconds_left / 60)
                    formatted_string = "{0}h:{1}m".format(
                        self.total_hours * -1,
                        self.final_minutes * -1
                    )

                    new_credits = member_credits + helpme_bonus
                    args = (new_credits, str(current_date), str(member_id), str(server_id), )
                    DatabaseHandler().update_database_with_args(
                        "UPDATE credit_bet SET credits = ?, \
                        lastClaimTime = ? WHERE userID = ? AND serverID = ?",
                        args
                    )
                    return await self.bot.say(
                        "{0.mention}, you have been given an additional {1} credits! " \
                        "Your 24 cooldown ended {2} ago!".format(
                            member,
                            helpme_bonus,
                            formatted_string
                        )
                    )
                else:
                    # should we output seconds too?
                    self.total_seconds = int(helpme_timer - self.total_seconds)
                    self.total_hours = int(self.total_seconds / 3600)
                    self.used_secs = int(self.total_hours * 3600)
                    self.seconds_left = int(self.total_seconds - self.used_secs)
                    self.final_minutes = int(self.seconds_left / 60)
                    final_seconds = int(self.seconds_left - (self.final_minutes * 60))
                    formatted_string = "{0}h:{1}m:{2}s".format(
                        self.total_hours,
                        self.final_minutes,
                        final_seconds
                    )
                    converted_hour = convert_seconds_to_hour(helpme_timer)
                    return await self.bot.say(
                        "{0.mention}, you can only use this command every {1} hours ({2}), " \
                        "and if at or below {3} credits :cry:".format(
                            member,
                            converted_hour,
                            formatted_string,
                            minimum_credits
                        )
                    )
Example #18
0
    async def update_config(self, ctx, update_section: str, update_key: str, *, update_value: str):
        """
        Update the configuration file

        :param ctx: discord.py Context
        :param update_section: section to be updated in the config file
        :param update_key: the key value to be updated in the passed in section
        :param update_value: the value that matches the key; this uses consume rest behavior
        """
        if update_section == 'ServerSettings':
            bot_message = await self.bot.say("This is a protected section.")
            await asyncio.sleep(5)
            await self.bot.delete_message(ctx.message)
            return await self.bot.delete_message(bot_message)
        else:
            try:
                member_id = ctx.message.author.id

                # @TODO : can we go back to using the regex option at some point? This is ugly...
                # This allows us to use #channel_name, @person_name
                update_value = update_value.replace('<@&', '')
                update_value = update_value.replace('<@!', '')
                update_value = update_value.replace('<#', '')
                update_value = update_value.replace('>', '')
                update_value = update_value.rstrip().lstrip()  # Strip out leading and trailing whitespace

                # Use regex to replace the characters added if they add via pinging; this causes whitespace issues
                # update_value = re.sub('[^\w]', '', update_value)

                bot_admin_users = []
                bot_admin_roles = []
                user_roles_list = []

                for user_role in ctx.message.author.roles:
                    user_roles_list.append(str(int(user_role.id)))

                try:
                    bot_admins_user_list = ConfigLoader().load_server_string_setting(
                        ctx.message.server.id,
                        'BotAdmins',
                        'bot_admin_users'
                    )

                    bot_admins_role_list = ConfigLoader().load_server_string_setting(
                        ctx.message.server.id,
                        'BotAdmins',
                        'bot_admin_roles'
                    )

                    if len(bot_admins_user_list) != 0:
                        for user in bot_admins_user_list.split():
                            bot_admin_users.append(user)

                    if len(bot_admins_role_list) != 0:
                        for role in bot_admins_role_list.split():
                            bot_admin_roles.append(role)

                except (configparser.NoSectionError, configparser.Error):
                    await self.bot.say("There was an error.  Please confirm the server configuration file exists "
                                       "via the genconfig command (only usable by server owner).")
                    pass

                # PEP8 formatting is amusing
                if update_section != 'BotAdmins':
                    if member_id == ctx.message.server.owner_id or \
                        int(member_id) == ConfigLoader().load_config_setting_int(
                            'BotSettings', 'owner_id'
                        ) or \
                        str(member_id) in bot_admin_users or \
                            [admin_role for admin_role in user_roles_list if admin_role in bot_admin_roles]:
                        filename = ctx.message.server.id
                        await self.update_config_file(
                            filename,
                            update_section,
                            update_key,
                            update_value,
                            ctx.message
                        )
                    else:
                        bot_message = await self.bot.say(
                            "Only the server owner can "
                            "configure different plugins."
                        )
                        await asyncio.sleep(5)
                        await self.bot.delete_message(ctx.message)
                        return await self.bot.delete_message(bot_message)
                elif update_section == 'BotAdmins':
                    if member_id == ctx.message.server.owner_id or \
                        int(member_id) == ConfigLoader().load_config_setting_int(
                            'BotSettings', 'owner_id'
                            ):
                        await self.bot.say(
                            "Please use the botadmin command to update this section."
                        )
            except (configparser.NoSectionError, configparser.NoOptionError) as config_error:
                print("Error with updating the configuration file: \n{0}".format(config_error))
Example #19
0
    async def on_join_assign_user_role(self, client, server_id: str, member: str):
        """

        :param client: the discord client object
        :param server_id: the discord server snowflake ID
        :param member: discord member object
        :return:
        """
        try:
            welcome_enabled = ConfigLoader().load_server_boolean_setting(
                server_id,
                'JoinPart',
                'assign_role_enabled'
            )

            if welcome_enabled:
                try:
                    join_assignment_role = ConfigLoader().load_server_int_setting(
                        server_id,
                        'JoinPart',
                        'role_assignment_id'
                    )

                    try:
                        if join_assignment_role != '':
                            guild = client.get_server(server_id)
                            for role in guild.roles:
                                # print("{0} - {1}".format(role.id, join_assignment_role))
                                if int(role.id) == join_assignment_role:
                                    # print("join_assignment_role = {0}".format(join_assignment_role))
                                    # print(role)
                                    await self.bot.add_roles(member, role)
                    except Exception as ex2:
                        return await ErrorLogging().log_error(
                            traceback.format_exception(
                                type(ex2),
                                ex2,
                                ex2.__traceback__
                            ),
                            member
                        )
                except Exception as ex:  # update this exception later to be more specific
                    await ErrorLogging().log_error(
                        traceback.format_exception(
                            type(ex),
                            ex,
                            ex.__traceback__
                        ),
                        member
                    )
                    pass
        except Exception as ex:  # update this exception later to be more specific
            await ErrorLogging().log_error(
                traceback.format_exception(
                    type(ex),
                    ex,
                    ex.__traceback__
                ),
                member
            )
            pass
        return
Example #20
0
    async def update_role_list(self, ctx, add_or_remove: str, user_or_role: str,
                               role_id: str):
        """
        Update the configured role list to add or remove a group.

        :param ctx: discord.py Context
        :param add_or_remove: (str) [add, remove] passed in string to determine
        if a role is being added or removed
        :param user_or_role: (str) [user, role] passed in string to determine
        if it's a user or a role that is being updated
        :param role_id: the discord snowflake ID for the role, the pinged username
        :return:
        """
        member_id = ctx.message.author.id
        server_id = str(ctx.message.server.id)

        updated_id_list = ''

        if member_id == ctx.message.server.owner_id or \
            int(member_id) == ConfigLoader().load_config_setting_int(
                'BotSettings', 'owner_id'
            ):
            if add_or_remove != 'add' and add_or_remove != 'remove':
                return await self.bot.say("Please specify if I am adding or removing a botadmin.")

            if user_or_role != 'user' and user_or_role != 'role':
                return await self.bot.say(
                    "Please specify if it's the user or role "
                    "list I am updating."
                )

            current_id_list = ConfigLoader().load_server_string_setting(
                server_id,
                'BotAdmins',
                'bot_admin_users' if user_or_role == 'user' else 'bot_admin_roles'
            )

            # @TODO : verify this works and remove commented out code
            # role_id = role_id.replace('<@&', '')
            # role_id = role_id.replace('<@!', '')
            # role_id = role_id.replace('>', '')
            # role_id = role_id.strip()
            role_id = re.sub('[^0-9]', '', role_id)

            if add_or_remove == 'add':
                if not BotResources().contains_word(current_id_list, role_id):
                    if current_id_list == 'NOT_SET':
                        updated_id_list = role_id
                    else:
                        updated_id_list = current_id_list + " " + role_id
                else:
                    return await self.bot.say("Role already added.")

            if add_or_remove == 'remove':
                if BotResources().contains_word(current_id_list, role_id):
                    updated_id_list = current_id_list.replace(role_id, '')

                if updated_id_list.isspace() or len(updated_id_list) == 0:
                    updated_id_list = 'NOT_SET'

            filename = ctx.message.server.id
            await ConfigCommands(self.bot).update_config_file(
                filename,
                'BotAdmins',
                'bot_admin_users' if user_or_role == 'user' else 'bot_admin_roles',
                updated_id_list.strip(),
                ctx.message
            )
Example #21
0
async def on_message(message):
    """
    discord.py on_message

    Processes messages, and if the message is a command, will execute it.
    We do check if the command is in the whitelist - these commands do not require bot terms acceptance to run, as they
    are typically general use commands (e.g. accept).

    If the command is not in the whitelist, we check that the user has accepted the terms of service.  If they have,
    we process the command and move on.  If they have not, we inform them that they must accept the terms before
    they can use commands.
    """
    view = StringView(message.content)
    # invoked_prefix = COMMAND_PREFIX  # Can we remove this? It's reset immediately after

    invoked_prefix = discord.utils.find(view.skip_string, COMMAND_PREFIX)
    discord.utils.find(view.skip_string, COMMAND_PREFIX)

    # This is fairly worthless.  While it can purge the message, everyone will still get a notification that there
    # was a message for them.  That's on Discord themselves to correct if the message is deleted.
    if "@everyone" in message.content:
        await Moderation(CLIENT).purge_everyone_message(message)

    if invoked_prefix is None:
        return

    invoker = view.get_word()

    if invoker in CLIENT.commands:
        # If the message content is a command within the whitelist, run the command; otherwise, they must have accepted
        # the bot terms before the command can be used.
        if message.content in whitelist:
            await CLIENT.process_commands(message)
        else:
            can_use = BotResources().check_accepted(message.author.id)
            message_channel_valid = False
            if not message.channel.is_private:
                message_channel_valid = BotResources().get_tos_channel_valid(message.server.id)
            if can_use:
                await CLIENT.process_commands(message)
            elif not can_use and message_channel_valid:
                if message.author.id != CLIENT.user.id:
                    message_channel_id = ConfigLoader().load_server_int_setting(
                        message.server.id,
                        'ConfigSettings',
                        'not_accepted_channel_id')

                    bot_message = await CLIENT.send_message(
                        discord.Object(id=message_channel_id),
                        NOT_ACCEPTED_MESSAGE.replace(
                            "{user}", message.author.mention).replace(
                                "{prefix}", COMMAND_PREFIX))
                    await asyncio.sleep(20)
                    await CLIENT.delete_message(bot_message)
            else:
                # This is needed to prevent infinite looping message posting
                if message.author.id != CLIENT.user.id:
                    bot_message = await CLIENT.send_message(
                        discord.Object(id=message.channel.id),
                        NOT_ACCEPTED_MESSAGE.replace(
                            "{user}", message.author.mention).replace(
                                "{prefix}", COMMAND_PREFIX))
                    await asyncio.sleep(20)
                    await CLIENT.delete_message(bot_message)
Example #22
0
from resources.config import ConfigLoader
from resources.bot_resources import BotResources

import discord
from discord.ext.commands.view import StringView
from discord.ext import commands


BOT_VERSION = "2.0.12"


# Check if there is a valid niftybot.ini file
# If no file is found, generate the file and then exit the bot via SystemExit
# @TODO: likely need the same check as the logout function runs, in case the bot is being
# run via systemd which will just keep restarting the bot over and over
BOT_CONFIG_GENERATED = ConfigLoader().check_for_bot_config()
if not BOT_CONFIG_GENERATED:
    print("Please configure the newly generated niftybot.ini file before restarting the bot.")
    raise SystemExit

# Not sure we still need this, but going to just keep it for now
DESCRIPTION = ConfigLoader().load_config_setting('BotSettings', 'description')

# Load the command prefix from the core ini
COMMAND_PREFIX = ConfigLoader().load_config_setting('BotSettings', 'command_prefix')

# Load the bot token from the core ini
BOT_TOKEN = ConfigLoader().load_config_setting('BotSettings', 'bot_token')

# Set the game name from the core ini, including the version if applicable
GAME_NAME = ConfigLoader().load_config_setting('BotSettings', 'game_name').replace("{version}", BOT_VERSION)
    async def update_role_list(self,
                               ctx,
                               add_or_remove: str,
                               role_id: str,
                               member: discord.Member = None):
        """
        Update the configured role list to add or remove a group. Command is executed via the `role` command.

        Examples:
            > role add Test
            Configuration file updated.

            > role add Test
            Role already added.

            > role test Test
            Please specify if I am adding or removing a role.

            > role remove Test
            Configuration file updated.

        :param ctx: discord.py Context
        :param add_or_remove: (str) [add, remove] passed in string to determine if a role is being added or removed
        :param role_id: discord snowflake ID for the role, can be added via direct pinging of the role
        :param member: optional discord.Member object
        :return:
        """
        member = ctx.message.author
        server_id = str(ctx.message.server.id)

        if member is not None:
            if add_or_remove != 'add' and add_or_remove != 'remove':
                return await self.bot.say(
                    "Please specify if I am adding or removing a role.")

            current_role_list = ConfigLoader().load_server_string_setting(
                server_id, 'RoleAssignment', 'role_list')

            # Somewhat ugly fix for when mentioning the role to strip stuff out
            role_id = role_id.replace('<@&', '')
            role_id = role_id.replace('>', '')
            role_id = role_id.strip()

            updated_role_list = ''

            if add_or_remove == 'add':
                if not BotResources().contains_word(current_role_list,
                                                    role_id):
                    if current_role_list == 'NOT_SET':
                        updated_role_list = role_id
                    else:
                        updated_role_list = current_role_list + " " + role_id
                else:
                    return await self.bot.say("Role already added.")

            if add_or_remove == 'remove':
                if BotResources().contains_word(current_role_list, role_id):
                    updated_role_list = current_role_list.replace(role_id, '')

                if updated_role_list.isspace() or len(updated_role_list) == 0:
                    updated_role_list = 'NOT_SET'

            filename = ctx.message.server.id
            await ConfigCommands(self.bot).update_config_file(
                filename, 'RoleAssignment', 'role_list',
                updated_role_list.strip(), ctx.message)
    async def build(self,
                    ctx,
                    game_type: str,
                    *,
                    character_name: str,
                    member: discord.Member = None):
        """ Get PvE, WvW, PvP build info for supplied character. """
        member = ctx.message.author
        member_id = ctx.message.author.id

        server_id = str(ctx.message.server.id)

        plugin_enabled = ConfigLoader().load_server_boolean_setting(
            server_id, 'ApiCommands', 'enabled')

        # Each new part of the name needs to be upper case, so firstly we will
        # make everything lower case and then do the upper casing
        character_name = character_name.lower()
        character_name = ' '.join(word[0].upper() + word[1:]
                                  for word in character_name.split())

        # lower case the game type, just in case
        game_type = game_type.lower()

        # to make this work, check if the plugin is in the list
        if member is not None and plugin_enabled:
            row = DatabaseHandler().fetch_results(
                """SELECT api_key FROM api WHERE discord_id = {0}""".format(
                    member_id))

            if row is not None:
                try:
                    character_name = character_name.replace(" ", "%20")

                    returned_skill_ids = await self.get_skill_ids(
                        character_name, row[0], game_type)

                    returned_char_info = await self.get_character_level(
                        row[0], character_name)

                    returned_trait_ids = await self.get_trait_ids(
                        character_name, row[0], game_type)

                    returned_skill_data = await self.get_skill_data(
                        returned_skill_ids)
                    returned_trait_data = await self.get_trait_data(
                        returned_trait_ids)

                    return_string = ("{0.mention}: \n"
                                     "```{1}```\n\n"
                                     "{2}\n\n"
                                     "{3}".format(member, returned_char_info,
                                                  returned_trait_data,
                                                  returned_skill_data))

                    return await self.bot.say(return_string)
                except urllib.error.HTTPError as error_code:
                    if error_code.code == 400:
                        print("{0}".format(character_name))
                        print("{0}".format(game_type))
                        print("{0}".format(error_code))
                        await self.bot.say("Character not found.")
                    else:
                        print(
                            "There was an error with the build command: {0}.".
                            format(error_code))
                    return
            else:
                return await self.bot.say(
                    "{0.mention}, please private message me your API key.".
                    format(member))
    def assign_role(self, ctx, *, guild: str, member: discord.Member = None):
        """
        Assign users to configured roles if requested.  Command is executed via the `guild` command.

        Examples:
            > guild Test
            {user.mention}: You've been successfully added to {guild_name}.

            > guild Test
            {user.mention}: You've been removed from {guild_name}.

        :param ctx: discord.py Context
        :param guild: the requested group name, uses consume rest behavior
        :param member: optional discord.Member object
        :return: Nothing
        """
        server_id = ctx.message.server.id

        if member is None:
            member = ctx.message.author

        plugin_enabled = ConfigLoader().load_server_boolean_setting(
            server_id, 'RoleAssignment', 'enabled')

        if member is not None and plugin_enabled:
            requested_guild = discord.utils.get(ctx.message.server.roles,
                                                name=guild)

            if requested_guild is None:
                # We ran into an issue where a role name was using acute accents
                # This is the attempt to fix that if requested_guild is none
                # If still none after this we'll need to get examples to fix it
                guild = guild.replace("'", "’")
                requested_guild = discord.utils.get(ctx.message.server.roles,
                                                    name=guild)

            role_list = ConfigLoader().load_server_string_setting(
                server_id, 'RoleAssignment', 'role_list')

            assignment_channel_list = ConfigLoader(
            ).load_server_string_setting(server_id, 'RoleAssignment',
                                         'assignment_channel_id')

            if role_list == 'NOT_SET' or assignment_channel_list == 'NOT_SET':
                yield from self.bot.say(
                    "This plugin is not configured for this server.")
                return

            channel_list = []
            for channel in map(int, assignment_channel_list.split()):
                channel_list.append(channel)

            if requested_guild is not None:

                role_list_split = []
                for role in map(int, role_list.split()):
                    role_list_split.append(role)

                if int(ctx.message.channel.id) in channel_list and \
                        int(requested_guild.id) in role_list_split:
                    for role in ctx.message.author.roles:
                        if role.id == requested_guild.id:
                            yield from self.bot.remove_roles(
                                ctx.message.author, requested_guild)
                            yield from self.bot.send_message(
                                ctx.message.channel,
                                "{0.mention}: You've been removed from {1}.".
                                format(member, requested_guild.name))
                            return

                    # So we got this far, add the user to the role
                    yield from self.bot.add_roles(ctx.message.author,
                                                  requested_guild)
                    yield from self.bot.send_message(
                        ctx.message.channel,
                        "{0.mention}: You've been successfully "
                        "added to {1}!".format(member, requested_guild.name))
                    return
        return
Example #26
0
 def __init__(self, bot):
     self.bot = bot
     self.owner_id = ConfigLoader().load_config_setting_int(
         'BotSettings', 'owner_id')