Пример #1
0
async def kick_member(bot, context): 
    """Deletes member from spreadsheet."""
    global gc
    family_name = context.arguments[0]
    family_name = family_name.lower()
    author_id = context.author.id
    response = Response()


    # VAR
    index_of_member_list = None
    list_of_family_names = []
    index_of_user = None

    # Check for malicious family name.
    if not (len(family_name) > 1 and '=' not in family_name[0]):
        response.content = f'{family_name} is not a valid family name.'
        return response

    # opens spreadsheet
    sh = await utilities.future(gc.open, SPREADSHEET_NAME)

    # gets all available worksheets
    worksheet = await utilities.future(sh.worksheets)

    # get index of member list
    for i, sheet in enumerate(worksheet):
        if MEMBER_LIST_NAME in str(sheet):
            index_of_member_list = i

    if index_of_member_list == None:
        response.content = 'Something went wrong when initalizing sheets (check member list name).'
        return response

    # get member list
    form_member_data = await utilities.future(sh.get_worksheet, index_of_member_list)
    form_member_list = await utilities.future(form_member_data.get_all_values)
    for i, row in enumerate(form_member_list):
        if i >= 4: # names start on row 4 here
            if len(row[0]) != 0:
                list_of_family_names.append(row[0].lower())

    # invalid family name
    if family_name not in list_of_family_names:
        response.content = f'{family_name} not a valid family name.'
        return response

    # get index of user
    index_of_user = list_of_family_names.index(family_name)
    index_of_user += 5 # offset, sheet specific

    # deletes entries in that row
    await utilities.future(form_member_data.update, f'A{index_of_user}:E{index_of_user}', [['', '', '', '', '']], value_input_option='user_entered')

    form_member_data.sort((1, 'asc'), range='A5:Z105')

    current_time = datetime.datetime.now().strftime('%m/%d/%Y %H:%M:%S')
    response.content = f'<@{author_id}> successfully kicked {family_name} on {current_time} from the spreadsheet.'
    return response
Пример #2
0
async def take_attendance(bot, context):
    """Takes all users in voice channel and logs it."""
    response = Response()

    # VARS
    attendance_list = [] 
    day_of_week = None  # 0 = Monday, 6 = Sunday
    index_of_nw_attendance = None

    # checks to see if user is in voice channel
    if not context.author.voice:
       raise CBException('You must be in a voice channel to use this feature.')

    voice_channel = context.author.voice.channel

    # get all members within voice channel
    for member in voice_channel.members:
        attendance_list.append(member)

    if len(attendance_list) == 1:
        raise CBException('Are you really node warring with yourself? Loser.')

    # get day
    day_of_week = datetime.datetime.today().weekday()
    if day_of_week == 5:
        raise CBException('Since when did Influence siege? lmfao pvx guild btw')

    # opens spreadsheet + nw attendance
    sh = await utilities.future(gc.open, SPREADSHEET_NAME)
    worksheet = await utilities.future(sh.worksheets)

    # get index of nw attendance
    for i, sheet in enumerate(worksheet):
        if NW_ATTENDANCE_NAME in str(sheet):
            index_of_nw_attendance = i

    nw_attendance = await utilities.future(sh.get_worksheet, index_of_nw_attendance)


    # error handling
    if index_of_nw_attendance == None:
        response.content = 'Something went wrong when initializing sheets (check nw attendance name).'
        return response

    for index in range(len(attendance_list)):
        if day_of_week == 6:  # if sunday
            await utilities.future(nw_attendance.update_cell, 3+index, NW_SUNDAY, str(attendance_list[index]))
        else:
            await utilities.future(nw_attendance.update_cell, 3+index, NW_MONDAY+day_of_week, str(attendance_list[index]))

    response.content = 'Attendance successfully taken.'
    return response
Пример #3
0
async def get_response(bot, context):
    response = Response()
    if context.author.voice:
        voice_channel = context.author.voice.channel
        voice_client = await utilities.join_and_ready(bot, voice_channel)

        options = {'format': 'bestaudio/best', 'noplaylist': True}
        downloader = YoutubeDL(options)
        url = context.arguments[0]
        try:
            file_location = data.get_from_cache(bot, None, url=url)
            if not file_location:
                logger.info("Not found in cache. Downloading...")
                info = await utilities.future(downloader.extract_info,
                                              url,
                                              download=False)
                download_url = info['formats'][0]['url']
                file_location = await data.add_to_cache(bot,
                                                        download_url,
                                                        name=url)
            ffmpeg_options = '-protocol_whitelist "file,http,https,tcp,tls"'
            voice_client.play(
                discord.FFmpegPCMAudio(file_location,
                                       before_options=ffmpeg_options))
        except BotException as e:
            raise e  # Pass up
        except Exception as e:
            raise CBException("Something bad happened.", e=e)
        response.content = "Playing your stuff."
    else:
        raise CBException("You're not in a voice channel.")

    return response
Пример #4
0
async def to_be_belled(bot, context):
    server = context.arguments[0]
    bell_minutes = context.arguments[1]
    
    response = Response()
    
    # check inputs
    if server not in SERVERS:
        response.content = '{} is not a valid server.'.format(server)
        return response
    if bell_minutes < 1 or bell_minutes > 60:
        response.content = 'The bell time must be between 1 and 60 minutes.'
        return response
    
    # passes checks, update BELL_SERVERS
    BELL_SERVERS[server] = ['YES', bell_minutes, round(time.time())]
Пример #5
0
async def get_response(bot, context):
    response = Response()
    if context.author.voice:
        voice_channel = context.author.voice.channel
        voice_client = await utilities.join_and_ready(bot, voice_channel)

        options = {'format': 'bestaudio/best', 'noplaylist': True}
        downloader = YoutubeDL(options)
        url = context.arguments[0]
        try:
            file_location = data.get_from_cache(bot, None, url=url)
            if not file_location:
                logger.info("Not found in cache. Downloading...")
                info = await utilities.future(downloader.extract_info, url, download=False)
                download_url = info['formats'][0]['url']
                file_location = await data.add_to_cache(bot, download_url, name=url)
            ffmpeg_options = '-protocol_whitelist "file,http,https,tcp,tls"'
            voice_client.play(discord.FFmpegPCMAudio(file_location, before_options=ffmpeg_options))
        except BotException as e:
            raise e  # Pass up
        except Exception as e:
            raise CBException("Something bad happened.", e=e)
        response.content = "Playing your stuff."
    else:
        raise CBException("You're not in a voice channel.")

    return response
Пример #6
0
 async def _get_response(self, context):
     """Takes a context and builds a response."""
     response = await commands.execute(self, context)
     if response is None:
         response = Response()
     elif self.selfbot and response.content:
         response.content = '\u200b' + response.content
     return response
Пример #7
0
async def get_response(bot, context):
    response = Response()
    use_plugin = configurations.get(bot, __name__, key='enable')
    if not use_plugin:
        response.content = (
            "The GDQ plugin is currently disabled. (GDQ is probably over or hasn't started yet)")
        return response

    embed_template = discord.Embed(
        title='Games Done Quick', url='https://gamesdonequick.com/',
        colour=discord.Colour(0x00aff0),
        description='\[ [Stream]({}) ] \[ [Schedule]({}) ] \[ [Donate]({}) ]'.format(
            configurations.get(bot, __name__, 'stream_url'),
            configurations.get(bot, __name__, 'schedule_url'),
            configurations.get(bot, __name__, 'donate_url')))
    embed_template.set_thumbnail(url='http://i.imgur.com/GcdqhUR.png')
    guild_id = context.guild.id if context.guild else None
    if context.index == 0:
        embed_template.add_field(name='Donation stats', value='Loading...', inline=False)
        response.game_index = data.get(bot, __name__, 'current_index', volatile=True, default=0)
        schedule_data = data.get(bot, __name__, 'schedule', volatile=True)
        games_list = schedule_data[response.game_index:response.game_index + 5]
        game_data = _embed_games_information(bot, games_list, guild_id)
        value = '\n\n'.join('**{}**\n{}'.format(*it) for it in game_data)
        embed_template.add_field(name='Schedule', value=value, inline=False)
        response.update_stats = True
        response.update_task = None
        response.message_type = MessageTypes.INTERACTIVE
        response.extra_function = gdq_menu
        response.extra = {'buttons': ['⬅', '⏺', '➡']}

    elif context.index == 1:  # About
        embed_template.add_field(name='About', value=(
            "Games Done Quick (GDQ) is a week-long charity gaming marathon that "
            "brings together speedrunners from around the globe to raise money on a "
            "livestream. They are currently supporting {0}, and all donations go "
            "directly to the charity.\n\nCheck out the links above for the Twitch "
            "stream, games schedule, and the donation portal!").format(
                configurations.get(bot, __name__, 'charity')))

    elif context.index == 2:  # Status
        status_text = await _get_status(bot)
        embed_template.add_field(name='Status', value=status_text, inline=False)

    elif context.index == 3:  # Current game
        embed_data = _get_current_game(bot, guild_id)[0]
        embed_template.add_field(name=embed_data[0], value=embed_data[1], inline=False)

    elif context.index == 4:  # Next game(s)
        embed_data = _get_next_games(bot, context.arguments[0], guild_id)
        for name, value in embed_data:
            embed_template.add_field(name=name, value=value, inline=False)

    elif context.index == 5:  # Search
        embed_data = _search_games(bot, context.arguments[0], guild_id=guild_id)
        embed_template.add_field(name=embed_data[0], value=embed_data[1], inline=False)

    elif context.index == 6:  # Notify
        game = _search_games(bot, context.arguments[0], return_game=True)
        response.content = _toggle_notification(
            bot, game, context, use_channel='channel' in context.options)
        embed_template = None

    response.embed = embed_template
    return response
Пример #8
0
        async def on_message(self, message, replacement_message=None):
            # Ensure bot can respond properly
            try:
                initial_data = self.can_respond(message)
            except Exception as e:  # General error
                logger.error(e)
                logger.error(traceback.format_exc())
                self.last_exception = e
                return
            if not initial_data:
                return

            # Ensure command is valid
            content = initial_data[0]
            elevation = 3 - (initial_data[4:0:-1] + [True]).index(True)
            split_content = content.split(' ', 1)
            if len(split_content) == 1:  # No spaces
                split_content.append('')
            base, parameters = split_content
            base = base.lower()
            try:
                command = self.commands[base]
            except KeyError:
                logger.debug("Suitable command not found: " + base)
                return

            # Check that user is not spamming
            author_id = message.author.id
            direct = isinstance(message.channel, PrivateChannel)
            spam_value = self.spam_dictionary.get(author_id, 0)
            if elevation > 0 or direct:  # Moderators ignore custom limit
                spam_limit = self.spam_limit
            else:
                spam_limit = min(
                    self.spam_limit,
                    data.get(self,
                             'core',
                             'spam_limit',
                             guild_id=message.guild.id,
                             default=self.spam_limit))
            if spam_value >= spam_limit:
                if spam_value == spam_limit:
                    self.spam_dictionary[author_id] = spam_limit + 1
                    plugins.broadcast_event(self, 'bot_on_user_ratelimit',
                                            message.author)
                    await self.send_message(
                        message.channel,
                        "{0}, you appear to be issuing/editing "
                        "commands too quickly. Please wait {1} seconds.".
                        format(message.author.mention, self.spam_timeout))
                return

            # Parse command and reply
            try:
                context = None
                with message.channel.typing():
                    logger.debug(message.author.name + ': ' + message.content)
                    subcommand, options, arguments = parser.parse(
                        self, command, parameters, message)
                    context = self.Context(
                        message, base, subcommand, options, arguments,
                        subcommand.command.keywords, initial_data[0],
                        elevation, message.guild, message.channel,
                        message.author, direct, subcommand.index,
                        subcommand.id, self)
                    plugins.broadcast_event(self, 'bot_on_command', context)
                    logger.info([subcommand, options, arguments])
                    response = await commands.execute(self, context)
                    if response is None:
                        response = Response()
                    if self.selfbot and response.content:
                        response.content = '\u200b' + response.content
            except Exception as e:  # General error
                response = Response()
                destination = message.channel
                message_reference = await self.handle_error(
                    e,
                    message,
                    context,
                    response,
                    edit=replacement_message,
                    command_editable=True)

            else:  # Attempt to respond
                send_arguments = response.get_send_kwargs(replacement_message)
                try:
                    destination = response.destination if response.destination else message.channel
                    message_reference = None
                    if replacement_message:
                        try:
                            await replacement_message.edit(**send_arguments)
                            message_reference = replacement_message
                        except discord.NotFound:  # Message deleted
                            response = Response()
                            message_reference = None
                    elif (not response.is_empty() and
                          not (self.selfbot and
                               response.message_type is MessageTypes.REPLACE)):
                        message_reference = await destination.send(
                            **send_arguments)
                    response.message = message_reference
                    plugins.broadcast_event(self, 'bot_on_response', response,
                                            context)
                except Exception as e:
                    message_reference = await self.handle_error(
                        e,
                        message,
                        context,
                        response,
                        edit=replacement_message,
                        command_editable=True)

            # Incremement the spam dictionary entry
            if author_id in self.spam_dictionary:
                self.spam_dictionary[author_id] += 1
            else:
                self.spam_dictionary[author_id] = 1

            # MessageTypes:
            # NORMAL - Normal. The issuing command can be edited.
            # PERMANENT - Message is not added to the edit dictionary.
            # REPLACE - Deletes the issuing command after 'extra' seconds. Defaults
            #   to 0 seconds if 'extra' is not given.
            # ACTIVE - The message reference is passed back to the function defined
            #   with 'extra_function'. If 'extra_function' is not defined, it will call
            #   plugin.handle_active_message.
            # INTERACTIVE - Assembles reaction buttons given by extra['buttons'] and
            #   calls 'extra_function' whenever one is pressed.
            # WAIT - Wait for event. Calls 'extra_function' with the result, or None
            #   if the wait timed out.
            #
            # Only the NORMAL message type can be edited.

            response.message = message_reference
            if message_reference and isinstance(message_reference.channel,
                                                PrivateChannel):
                permissions = self.user.permissions_in(
                    message_reference.channel)
            elif message_reference:
                permissions = message_reference.guild.me.permissions_in(
                    message_reference.channel)
            else:
                permissions = None
            self.last_response = message_reference

            if response.message_type is MessageTypes.NORMAL:
                # Edited commands are handled in base.py
                if message_reference is None:  # Forbidden exception
                    return
                wait_time = self.edit_timeout
                if wait_time:
                    self.edit_dictionary[str(message.id)] = message_reference
                    await asyncio.sleep(wait_time)
                    if str(message.id) in self.edit_dictionary:
                        del self.edit_dictionary[str(message.id)]
                        if message_reference.embeds:
                            embed = message_reference.embeds[0]
                            if embed.footer.text and embed.footer.text.startswith(
                                    '\u200b' * 3):
                                embed.set_footer()
                                try:
                                    await message_reference.edit(embed=embed)
                                except:
                                    pass

            elif response.message_type is MessageTypes.REPLACE:
                try:
                    if self.selfbot and not replacement_message:  # Edit instead
                        await message.edit(**send_arguments)
                    else:
                        if response.extra:
                            await asyncio.sleep(response.extra)
                        try:
                            await message.delete(reason='Automatic')
                        except:  # Ignore permissions errors
                            pass
                except Exception as e:
                    message_reference = await self.handle_error(
                        e, message, context, response, edit=message_reference)
                    self.last_response = message_reference

            elif response.message_type is MessageTypes.ACTIVE:
                if message_reference is None:  # Forbidden exception
                    return
                try:
                    await response.extra_function(self, context, response)
                except Exception as e:  # General error
                    message_reference = await self.handle_error(
                        e, message, context, response, edit=message_reference)
                    self.last_response = message_reference

            elif response.message_type is MessageTypes.INTERACTIVE:
                try:
                    buttons = response.extra['buttons']
                    kwargs = response.extra.get('kwargs', {})
                    if 'timeout' not in kwargs:
                        kwargs['timeout'] = 300
                    if 'check' not in kwargs:
                        kwargs['check'] = (lambda r, u: r.message.id ==
                                           message_reference.id and not u.bot)
                    for button in buttons:
                        await message_reference.add_reaction(button)
                    reaction_check = await destination.get_message(
                        message_reference.id)
                    for reaction in reaction_check.reactions:
                        if not reaction.me or reaction.count > 1:
                            async for user in reaction.users():
                                if user != self.user and permissions.manage_messages:
                                    asyncio.ensure_future(
                                        message_reference.remove_reaction(
                                            reaction, user))
                    await response.extra_function(self, context, response,
                                                  None, False)
                    process_result = True
                    while process_result is not False:
                        try:
                            if not permissions.manage_messages:
                                add_task = self.wait_for(
                                    'reaction_add', **kwargs)
                                remove_task = self.wait_for(
                                    'reaction_remove', **kwargs)
                                done, pending = await asyncio.wait(
                                    [add_task, remove_task],
                                    return_when=FIRST_COMPLETED)
                                result = next(iter(done)).result()
                                for future in pending:
                                    future.cancel()
                            else:  # Can remove reactions
                                result = await self.wait_for(
                                    'reaction_add', **kwargs)
                                if result[1] != self.user:
                                    asyncio.ensure_future(
                                        message_reference.remove_reaction(
                                            *result))
                                else:
                                    continue
                            is_mod = data.is_mod(self, message.guild,
                                                 result[1].id)
                            if (response.extra.get('reactionlock', True)
                                    and not result[0].me or
                                (response.extra.get('userlock', True) and
                                 not (result[1] == message.author or is_mod))):
                                continue
                        except (asyncio.futures.TimeoutError,
                                asyncio.TimeoutError):
                            await response.extra_function(
                                self, context, response, None, True)
                            process_result = False
                        else:
                            process_result = await response.extra_function(
                                self, context, response, result, False)
                    try:
                        await response.message.clear_reactions()
                    except:
                        pass
                except Exception as e:
                    message_reference = await self.handle_error(
                        e, message, context, response, edit=message_reference)
                    self.last_response = message_reference

            elif response.message_type is MessageTypes.WAIT:
                try:
                    kwargs = response.extra.get('kwargs', {})
                    if 'timeout' not in kwargs:
                        kwargs['timeout'] = 300
                    process_result = True
                    while process_result is not False:
                        try:
                            result = await self.wait_for(
                                response.extra['event'], **kwargs)
                        except asyncio.TimeoutError:
                            await response.extra_function(
                                self, context, response, None)
                            process_result = False
                        else:
                            process_result = await response.extra_function(
                                self, context, response, result)
                        if not response.extra.get('loop', False):
                            process_result = False

                except Exception as e:
                    message_reference = await self.handle_error(
                        e, message, context, response, edit=message_reference)
                    self.last_response = message_reference

            else:
                logger.error("Unknown message type: {}".format(
                    response.message_type))
            '''
Пример #9
0
async def get_response(bot, context):
    response = Response()
    use_plugin = configurations.get(bot, __name__, key='enable')
    if not use_plugin:
        response.content = (
            "The GDQ plugin is currently disabled. (GDQ is probably over or hasn't started yet)"
        )
        return response

    embed_template = discord.Embed(
        title='Games Done Quick',
        url='https://gamesdonequick.com/',
        colour=discord.Colour(0x00aff0),
        description='\[ [Stream]({}) ] \[ [Schedule]({}) ] \[ [Donate]({}) ]'.
        format(configurations.get(bot, __name__, 'stream_url'),
               configurations.get(bot, __name__, 'schedule_url'),
               configurations.get(bot, __name__, 'donate_url')))
    embed_template.set_thumbnail(url='http://i.imgur.com/GcdqhUR.png')
    guild_id = context.guild.id if context.guild else None
    if context.index == 0:
        embed_template.add_field(name='Donation stats',
                                 value='Loading...',
                                 inline=False)
        response.game_index = data.get(bot,
                                       __name__,
                                       'current_index',
                                       volatile=True,
                                       default=0)
        schedule_data = data.get(bot, __name__, 'schedule', volatile=True)
        games_list = schedule_data[response.game_index:response.game_index + 5]
        game_data = _embed_games_information(bot, games_list, guild_id)
        value = '\n\n'.join('**{}**\n{}'.format(*it) for it in game_data)
        embed_template.add_field(name='Schedule', value=value, inline=False)
        response.update_stats = True
        response.update_task = None
        response.message_type = MessageTypes.INTERACTIVE
        response.extra_function = gdq_menu
        response.extra = {'buttons': ['⬅', '⏺', '➡']}

    elif context.index == 1:  # About
        embed_template.add_field(
            name='About',
            value=
            ("Games Done Quick (GDQ) is a week-long charity gaming marathon that "
             "brings together speedrunners from around the globe to raise money on a "
             "livestream. They are currently supporting {0}, and all donations go "
             "directly to the charity.\n\nCheck out the links above for the Twitch "
             "stream, games schedule, and the donation portal!").format(
                 configurations.get(bot, __name__, 'charity')))

    elif context.index == 2:  # Status
        status_text = await _get_status(bot)
        embed_template.add_field(name='Status',
                                 value=status_text,
                                 inline=False)

    elif context.index == 3:  # Current game
        embed_data = _get_current_game(bot, guild_id)[0]
        embed_template.add_field(name=embed_data[0],
                                 value=embed_data[1],
                                 inline=False)

    elif context.index == 4:  # Next game(s)
        embed_data = _get_next_games(bot, context.arguments[0], guild_id)
        for name, value in embed_data:
            embed_template.add_field(name=name, value=value, inline=False)

    elif context.index == 5:  # Search
        embed_data = _search_games(bot,
                                   context.arguments[0],
                                   guild_id=guild_id)
        embed_template.add_field(name=embed_data[0],
                                 value=embed_data[1],
                                 inline=False)

    elif context.index == 6:  # Notify
        game = _search_games(bot, context.arguments[0], return_game=True)
        response.content = _toggle_notification(bot,
                                                game,
                                                context,
                                                use_channel='channel'
                                                in context.options)
        embed_template = None

    response.embed = embed_template
    return response
Пример #10
0
async def get_response(bot, context):
    """Gets a response given the parsed input.

    context attributes:
    bot -- A reference to the bot itself.
    message -- The discord.message object obtained from on_message.
    base -- The base command name that immediately follows the invoker.
    subcommand -- The subcommand that matched the parameters.
    index -- The index of the found subcommand.
    options -- A dictionary representing the options and potential positional
        arguments that are attached to them.
    arguments -- A list of strings that follow the syntax of the blueprint
        index for arguments following the options.
    keywords -- Another list of strings that holds all option keywords. These
        can be used to prevent database conflicts with user commands.
    cleaned_content -- Simply the message content without the invoker.
    """

    # This is what the bot will say when it returns from this function.
    # The response object can be manipulated in many ways. The attributes of
    #   the response will be passed into the send function.
    response = Response()
    response.content = ''  # Default

    # Set to True if you want your message read with /tts (not recommended).
    response.tts = False  # Default

    # The message type dictates how the bot handles your returned message.
    #
    # NORMAL - Normal. The issuing command can be edited.
    # PERMANENT - Message is not added to the edit dictionary.
    # REPLACE - Deletes the issuing command after 'extra' seconds. Defaults
    #   to 0 seconds if 'extra' is not given.
    # ACTIVE - The message reference is passed back to the function defined
    #   with 'extra_function'. If 'extra_function' is not defined, it will call
    #   plugin.handle_active_message.
    # INTERACTIVE - Assembles reaction buttons given by extra['buttons'] and
    #   calls 'extra_function' whenever one is pressed.
    # WAIT - Wait for event. Calls 'extra_function' with the result, or None
    #   if the wait timed out.
    #
    # Only the NORMAL message type can be edited.
    response.message_type = MessageTypes.NORMAL  # Default

    # The extra variable is used for some message types.
    response.extra = None  # Default

    # Initially, check to make sure that you've matched the proper command.
    # If there is only one command specified, this may not be necessary.
    index, options, arguments = context.index, context.options, context.arguments
    if context.base == 'mycommand':

        # Then, the subcommand index will tell you which command syntax was
        #   satisfied. The order is the same as was specified initially.
        if index == 0:  # myoption
            response.content = "You called the first subcommand!"
            # Do other stuff...

        elif index == 1:  # custom/attached
            # To see if an optional option was included in the command, use:
            if 'custom' in options:
                response.content += "You included the \"custom\" flag!\n"
                # Do stuff relevant to this flag here...

            # To get the parameter attached to an option, simply access it from
            #   the options dictionary.
            if 'attached' in options:
                response.content += "The attached parmeter: {}\n".format(
                    options['attached'])

            # In case somebody was looking for the help...
            if len(options) == 0:
                invoker = utilities.get_invoker(bot, guild=context.guild)
                response.content += (
                    "You didn't use either flag...\n"
                    "For help, try `{}help mycommand`".format(invoker))

        elif index == 2:  # trailing arguments
            # If arguments are specified as trailing, they will be in a list.
            response.content += "The list of trailing arguments: {}".format(
                arguments)

        elif index == 3:  # grouped arguments
            # All arguments are grouped together as the first element
            response.message_type = MessageTypes.PERMANENT
            response.content = ("You can't edit your command here.\n"
                                "Single grouped argument: {}").format(
                                    arguments[0])

        elif index == 4:  # complex
            # This mixes elements of both examples seen above.
            response.content = ("The argument attached to the complex "
                                "option: {}").format(options['complex'])
            if 'other' in options:
                response.content += "\nThe other option has attached: {}".format(
                    options['other'])
            response.content += "\nLastly, the trailing arguments: {}".format(
                arguments)

        elif index == 5:  # (Very slow) marquee
            # This demonstrates the active message type.
            # Check active_marquee to see how it works.
            response.message_type = MessageTypes.ACTIVE
            response.extra_function = active_marquee  # The function to call
            response.extra = arguments[0]  # The text to use
            response.content = "Setting up marquee..."  # This will be shown first

    # Here's another command base.
    elif context.base == 'myothercommand':

        if index == 0:  # keyword checker
            text = arguments[0]
            if not text:
                response.content = "You didn't say anything...\n"
            else:
                response.content = "This is your input: {}\n".format(text)
                if text in context.keywords:
                    response.content += "Your input was in the list of keywords!\n"
                else:
                    response.content += (
                        "Your input was not in the list of keywords. "
                        "They are: {}\n").format(context.keywords)
            response.message_type = MessageTypes.PERMANENT
            response.delete_after = 15
            response.content += "This message will self destruct in 15 seconds."

        else:  # impossible command???
            raise CBException(
                "This is a bug! You should never see this message.")

    elif context.base == 'wait':
        response.message_type = MessageTypes.WAIT
        # The extra attribute should consist of a dictionary containing the
        #   event and any other kwargs. Most notably, you will likely want to
        #   define the check used in wait_for.
        response.extra_function = custom_interaction
        response.extra = {
            'event': 'message',
            'kwargs': {
                'timeout': 30,  # Default 300
                'check': lambda m: m.author == context.author,
            }
        }
        response.content = "Say something, {}.".format(context.author)

    return response
Пример #11
0
async def invite_member(bot, context): 
    """Adds member to spreadsheet."""
    global gc
    #family_name, discord_name = context.arguments
    family_name = context.arguments[0]
    family_name = family_name.lower()
    discord_name = context.arguments[1]
    author_id = context.author.id
    response = Response()
    
    # VAR
    index_of_member_list = None
    list_of_family_names = []
    index_of_user = None
    empty_index = 0

    # Check for malicious family name.
    if not (len(family_name) > 1 and '=' not in family_name[0]):
        response.content = f'{family_name} is not a valid family name.'
        return response

    if '=' == discord_name[0] or '#' not in discord_name:
        response.content = f'{discord_name} is not a valid Discord name. Cannot start with = or does not have a numeric identifier.'
        return response
   
    # opens spreadsheet
    sh = await utilities.future(gc.open, SPREADSHEET_NAME)

    # gets all available worksheets
    worksheet = await utilities.future(sh.worksheets)
   
    # get index of member list
    for i, sheet in enumerate(worksheet):
        if MEMBER_LIST_NAME in str(sheet):
            index_of_member_list = i

    if index_of_member_list == None:
        response.content = 'Something went wrong when initalizing sheets (check member list name).'
        return response

    # get member list
    form_member_data = await utilities.future(sh.get_worksheet, index_of_member_list)
    form_member_list = await utilities.future(form_member_data.get_all_values)
    for i, row in enumerate(form_member_list):
        if i >= 4: # names start on row 4 here
            if len(row[0]) != 0:
                list_of_family_names.append(row[0].lower())

    if family_name in list_of_family_names:
        response.content = f'{family_name} is already on the sheet!'
        return response
    
    for i, element in enumerate(form_member_list):
        if len(element[0]) > 1:
            empty_index = i
            print(element[0])
    print(empty_index)
    print(form_member_list[i])
    empty_index += 2 # index starts at 1 for sheets and +1 for offset

    if empty_index == 106:
        response.content = 'The guild is currently full!'
        return response

    current_time = datetime.datetime.now().strftime('%m/%d/%Y %H:%M:%S')
    current_date = datetime.datetime.now().strftime('%Y-%m-%d')

    # fill sheet
    await utilities.future(form_member_data.update_cell, empty_index, 1, family_name)
    await utilities.future(form_member_data.update_cell, empty_index, 2, discord_name)
    await utilities.future(form_member_data.update_cell, empty_index, 3, current_date)
    await utilities.future(form_member_data.update_cell, empty_index, 4, 'Apprentice')
    await utilities.future(form_member_data.update_cell, empty_index, 5, 'Active')

    form_member_data.sort((1, 'asc'), range='A5:Z105')

    response.content = f'<@{author_id}> successfully added {family_name} to sheet on {current_time}.'

    return response
Пример #12
0
async def update_to_sheet(bot, context):
    """Updates family name to spreadsheet."""
    global gc
    family_name, daily_pay_value = context.arguments
    family_name = family_name.lower()
    author_id = context.author.id
    response = Response()

    # check family name for malicious character

    if not (len(family_name) > 1 and '=' not in family_name[0]):
        response.content = f'{family_name} is not a valid family name.'
        return response


    # VAR
    index_of_form = None
    next_index = 0
    index_of_member_list = None
    list_of_family_names = []

    # opens spreadsheet
    sh = await utilities.future(gc.open, SPREADSHEET_NAME)

    # gets all available worksheets
    worksheet = await utilities.future(sh.worksheets)

    # get the index of the form we want
    for i, sheet in enumerate(worksheet):
        if FORM_NAME in str(sheet):
            index_of_form = i
        if MEMBER_LIST_NAME in str(sheet):
            index_of_member_list = i
            
    # checks to see if one of these doesn't exist
    if ((index_of_form is None) or (index_of_member_list is None)):
        response.content = 'Something went wrong when initializing sheets.'
        return response

    # getting member list
    form_member_data = await utilities.future(sh.get_worksheet, index_of_member_list)
    form_member_list = await utilities.future(form_member_data.get_all_values)
    for i, row in enumerate(form_member_list):
        if i > 4:  # names start on row 4 here, first column
            if len(row[0]) != 0:
                list_of_family_names.append(row[0].lower())

    # open the form sheet
    form_data = await utilities.future(sh.get_worksheet, index_of_form)
    form_values = await utilities.future(form_data.get_all_values)
    form = await utilities.future(sh.get_worksheet, index_of_form)

    # iterate over rows till we find an empty index
    for i, row in enumerate(form_values):
        if len(row[0]) != 0:
            next_index = i

    next_index += 2  # this is the new empty row, +1 for next row and +1 because index starts at 1
    current_time = datetime.datetime.now().strftime('%m/%d/%Y %H:%M:%S')

    # fill the sheet
    await utilities.future(form.update_cell, next_index, SHEET_TIMESTAMP, current_time)                 # row 1
    await utilities.future(form.update_cell, next_index, SHEET_FAMILY_NAME, family_name)                # row 2
    await utilities.future(form.update_cell, next_index, SHEET_OFFICER_NAME, str(context.author))       # row 4
    await utilities.future(form.update_cell, next_index, SHEET_DAILY_PAY_VALUE, daily_pay_value)        # row 5
    response.content = f'<@{author_id}> renewed {family_name} on {current_time} with a daily pay value of {daily_pay_value}'

    # well f**k
    if family_name not in list_of_family_names:
        response.content += f', however, {family_name} does not exist. Check spreadsheet/ask officer for help.'
    
    form.sort((1, 'des'))

    return response
Пример #13
0
async def get_response(bot, context):
    """Gets a response given the parsed input.

    context attributes:
    bot -- A reference to the bot itself.
    message -- The discord.message object obtained from on_message.
    base -- The base command name that immediately follows the invoker.
    subcommand -- The subcommand that matched the parameters.
    index -- The index of the found subcommand.
    options -- A dictionary representing the options and potential positional
        arguments that are attached to them.
    arguments -- A list of strings that follow the syntax of the blueprint
        index for arguments following the options.
    keywords -- Another list of strings that holds all option keywords. These
        can be used to prevent database conflicts with user commands.
    cleaned_content -- Simply the message content without the invoker.
    """

    # This is what the bot will say when it returns from this function.
    # The response object can be manipulated in many ways. The attributes of
    #   the response will be passed into the send function.
    response = Response()
    response.content = ''  # Default

    # Set to True if you want your message read with /tts (not recommended).
    response.tts = False  # Default

    # The message type dictates how the bot handles your returned message.
    #
    # NORMAL - Normal. The issuing command can be edited.
    # PERMANENT - Message is not added to the edit dictionary.
    # REPLACE - Deletes the issuing command after 'extra' seconds. Defaults
    #   to 0 seconds if 'extra' is not given.
    # ACTIVE - The message reference is passed back to the function defined
    #   with 'extra_function'. If 'extra_function' is not defined, it will call
    #   plugin.handle_active_message.
    # INTERACTIVE - Assembles reaction buttons given by extra['buttons'] and
    #   calls 'extra_function' whenever one is pressed.
    # WAIT - Wait for event. Calls 'extra_function' with the result, or None
    #   if the wait timed out.
    #
    # Only the NORMAL message type can be edited.
    response.message_type = MessageTypes.NORMAL  # Default

    # The extra variable is used for some message types.
    response.extra = None  # Default

    # Initially, check to make sure that you've matched the proper command.
    # If there is only one command specified, this may not be necessary.
    index, options, arguments = context.index, context.options, context.arguments
    if context.base == 'mycommand':

        # Then, the subcommand index will tell you which command syntax was
        #   satisfied. The order is the same as was specified initially.
        if index == 0:  # myoption
            response.content = "You called the first subcommand!"
            # Do other stuff...

        elif index == 1:  # custom/attached
            # To see if an optional option was included in the command, use:
            if 'custom' in options:
                response.content += "You included the \"custom\" flag!\n"
                # Do stuff relevant to this flag here...

            # To get the parameter attached to an option, simply access it from
            #   the options dictionary.
            if 'attached' in options:
                response.content += "The attached parmeter: {}\n".format(options['attached'])

            # In case somebody was looking for the help...
            if len(options) == 0:
                invoker = utilities.get_invoker(bot, guild=context.guild)
                response.content += ("You didn't use either flag...\n"
                                     "For help, try `{}help mycommand`".format(invoker))

        elif index == 2:  # trailing arguments
            # If arguments are specified as trailing, they will be in a list.
            response.content += "The list of trailing arguments: {}".format(arguments)

        elif index == 3:  # grouped arguments
            # All arguments are grouped together as the first element
            response.message_type = MessageTypes.PERMANENT
            response.content = ("You can't edit your command here.\n"
                                "Single grouped argument: {}").format(arguments[0])

        elif index == 4:  # complex
            # This mixes elements of both examples seen above.
            response.content = ("The argument attached to the complex "
                                "option: {}").format(options['complex'])
            if 'other' in options:
                response.content += "\nThe other option has attached: {}".format(options['other'])
            response.content += "\nLastly, the trailing arguments: {}".format(arguments)

        elif index == 5:  # (Very slow) marquee
            # This demonstrates the active message type.
            # Check active_marquee to see how it works.
            response.message_type = MessageTypes.ACTIVE
            response.extra_function = active_marquee  # The function to call
            response.extra = arguments[0]  # The text to use
            response.content = "Setting up marquee..."  # This will be shown first

    # Here's another command base.
    elif context.base == 'myothercommand':

        if index == 0:  # keyword checker
            text = arguments[0]
            if not text:
                response.content = "You didn't say anything...\n"
            else:
                response.content = "This is your input: {}\n".format(text)
                if text in context.keywords:
                    response.content += "Your input was in the list of keywords!\n"
                else:
                    response.content += ("Your input was not in the list of keywords. "
                                         "They are: {}\n").format(context.keywords)
            response.message_type = MessageTypes.PERMANENT
            response.delete_after = 15
            response.content += "This message will self destruct in 15 seconds."

        else:  # impossible command???
            raise CBException("This is a bug! You should never see this message.")

    elif context.base == 'wait':
        response.message_type = MessageTypes.WAIT
        # The extra attribute should consist of a dictionary containing the
        #   event and any other kwargs. Most notably, you will likely want to
        #   define the check used in wait_for.
        response.extra_function = custom_interaction
        response.extra = {
            'event': 'message',
            'kwargs': {
                'timeout': 30,  # Default 300
                'check': lambda m: m.author == context.author,
            }
        }
        response.content = "Say something, {}.".format(context.author)

    return response