Пример #1
0
async def scrape_website(client):
    """
    :param client: client bot is connected to
    :return: only if there's an issue
    Type '!scrape' to restart the scraping process.

    Note: this function is executed on bot_ready, so
    I have to work around not having a convenient
    guild object.
r    """

    debug_channel = utils.get_bot_commands_channel(client)
    await debug_channel.send(f"Started web scraping.")
    print(f"Web scraper starting...")

    # This loop will always run indefinitely.
    while True:

        # During this web scraping, first check if there was
        # any commands issued to force stop this functionality.
        if scraper.issued_off:
            game_lab_channel = utils.get_game_lab_channel(client)
            print(f"Successfully turned off webscraper")
            await debug_channel.send(
                f"Successfully turned off scraper.\n\nPlease go to {game_lab_channel.mention} and verify this action by comparing its edited timestamp."
            )
            scraper.issued_off = False
            scraper.is_scraping = False
            return

        # Secondly, check if the embeds exist.
        # It's possible someone may have deleted them mid-process.
        if not await validators.validate_pc_availability_embeds(client):
            print(
                f"...web scraping ending prematurely- embeds are missing! (This can be restarted with !scrape)"
            )
            await debug_channel.send(
                f"ERROR: Machine availability panels must first exist in the channel `#{debug_channel}`! You can add these panels by entering `!gamelab` inside the channel, then start auto-updating PC availability with `!scrape`."
            )
            return

        scraper.is_scraping = True

        pc_statuses = await _get_scraped_pc_availability()
        if pc_statuses is None:
            print(
                "Game Lab Availability is offline. Unable to get PC statuses. Restart bot with !restart."
            )
            break

        print(
            f"Updating PC availability with the following statuses:\n\t{pc_statuses}"
        )
        await update_machine_availability_embed(client, pc_statuses)
        print(F"Trying again in 5 seconds")
        await asyncio.sleep(5)

    return None
async def display_ping_check(ctx_or_client):

    last_day_of_month = calendar.monthrange(datetime.today().year, datetime.today().month)[1]

    # TODO: Get announcements and leadership chat into config
    try:
        ping_channel = discord.utils.get(ctx_or_client.guild.channels, name="announcements")

        if datetime.today().day == last_day_of_month:
            report_channel = discord.utils.get(ctx_or_client.guild.channels, name="leadership-chat")
        else:
            report_channel = utils.get_bot_commands_channel(ctx_or_client.guild)

    # TODO: Fix up guild differentiation
    except AttributeError:
        guild = ctx_or_client.get_guild(int(config['id-guild']['id']))
        ping_channel = discord.utils.get(guild.channels, name="announcements")

        if datetime.today().day == last_day_of_month:
            report_channel = discord.utils.get(guild.channels, name="leadership-chat")
        else:
            report_channel = utils.get_bot_commands_channel(guild)

    first_day_of_month = datetime.today().replace(day=1)
    msgs = [msg async for msg in ping_channel.history(limit=100, before=None, after=first_day_of_month, around=None, oldest_first=None)]
    user_pings = {}
    total_pings = 0
    for msg in msgs:
        if "@everyone" in msg.content:
            total_pings += 1
            try:
                user_pings[msg.author] += 1
            except KeyError:
                user_pings[msg.author] = 1

    embed = discord.Embed(title=" ",
                          description=f"`Description`: The total of users who have pinged @everyone in {ping_channel.mention} since {calendar.month_name[datetime.today().month]} 1, {datetime.today().year}.",
                          color=0xff961f)
    embed.set_author(name="Ping Check - Report")
    embed.set_thumbnail(url="https://i.redd.it/4t5g9j86khp21.png")
    embed.set_footer(text=f"Total pings: {total_pings}")

    for user, pings in user_pings.items():
        embed.add_field(name=f"User total: {pings}", value=f"{user.mention}", inline=True)
    await report_channel.send(embed=embed)
Пример #3
0
async def force_off(guild: discord.guild):

    debug_channel = utils.get_bot_commands_channel(guild)

    try:
        scraper.issued_off = True
        await debug_channel.send(f"Turning off webscraper, please wait...")
    except Exception as e:
        print(f"Unable to force off!")
        await debug_channel.send(
            f"Exception caught trying to turn off webscraper:\n\n{e}")
Пример #4
0
async def on_command_error(ctx, error):

    message = f"Command error or exception found! See below:\n\nCOMMAND - `{ctx.message.content}`\nERROR - `{error}`\nSENT BY - `{ctx.author}`\nFAILED AT - {ctx.channel.mention}\n\nFULL TRACEBACK:```python\n{error}```"
    print(dir(ctx))
    print(dir(error))

    owner = utils.get_codebase_owner_member(ctx.guild)
    commands_channel = utils.get_bot_commands_channel(ctx.guild)
    if owner:
        message += f"\n\n{owner.mention}"

    if owner and commands_channel is None:
        await owner.send(f"{message}")
    else:
        await commands_channel.send(message)
Пример #5
0
    async def restart_app(self, context):

        print(F"Restarting bot!")

        bot_channel = utils.get_bot_commands_channel(context.guild)

        if self.is_authenticated() and [
                dyno.state for dyno in self.app.dynos()
        ]:
            await bot_channel.send(
                "Restarting bot from Heroku- please wait approximately 15 seconds..."
            )
            self.app.restart()
        else:
            await bot_channel.send(
                "Will not restart- this bot must be running on Heroku")
Пример #6
0
async def twitterpoll(ctx):
    """
    Start the Twitter streaming process
    :param ctx: context
    :return: None
    """

    try:
        await asyncio.wait([
            twitterfeed.twitter_poller.poll_for_data_from_stream(client),
            twitterfeed.twitter_poller.poll_for_tweet_updates(),
        ])
    except Exception as last_resort:
        commands_channel = utils.get_bot_commands_channel(ctx.guild)
        owner = utils.get_codebase_owner_member(ctx.guild)
        await commands_channel.send(
            f"{owner.mention}, all exceptions were tried against the Twitter streamer. The following was captured:\n{last_resort}\n\nIt is highly recommended to execute `!twitterstream` again."
        )
Пример #7
0
async def send_faq_embed(context):

    await context.message.delete()

    faq = utils.get_faq_and_a()
    faq_channel = utils.get_faq_channel(context.guild)
    help_dir_channel = utils.get_help_directory_channel(context.guild)

    if faq_channel is None:
        bot_channel = utils.get_bot_commands_channel(context.guild)
        await bot_channel.send(f"Missing FAQ channel!")

    try:  # Questions are not a part of the config file
        questions_channel = discord.utils.get(context.guild.channels,
                                              name="questions")
    except Exception:
        questions_channel = None

    if questions_channel is None or help_dir_channel is None:
        embed = discord.Embed(
            title=" ",
            description="Please view our available resources for more help.",
            color=0x52fffc)
    else:
        embed = discord.Embed(
            title=" ",
            description=
            f"For any additional questions, please see {questions_channel.mention} or {help_dir_channel.mention}!",
            color=0x52fffc)
    embed.set_author(name="❔ FAQ")
    embed.set_thumbnail(
        url=
        "https://lh3.googleusercontent.com/proxy/NuskMuMLeEstVyxBKL5OLLQ4V-rULdK0fygraiaeqFaWVclGTaxCXz7RjVurr2GsZvS2ijr5H9_3wZPuPPRAYd5Vg-Q"
    )

    for q_and_a in faq:
        embed.add_field(name=q_and_a[0].capitalize(),
                        value=q_and_a[1],
                        inline=False)

    await context.send(embed=embed)
Пример #8
0
async def on_ready():

    print(f"On ready...")
    after = time.time()
    milliseconds = 1000 * (after - before)
    print(f"...bot ready! (in {milliseconds} milliseconds!)")

    channel = utils.get_bot_commands_channel(client)

    if channel:
        await channel.send(
            f"Bot successfully started in `{milliseconds}` milliseconds.\n\nTwitter poller needs to be started with `!twitterpoll`. See `!metrics`."
        )

    print(F"Checking everyone pings...")
    await servermetrics.display_ping_check(client)

    # TODO: Automatically update GM panels and leadership panels on setup

    print(f"Starting web scraper...")
    await asyncio.wait([gamelabscraper.scrape_website(client)])
Пример #9
0
async def populate_channel_with_tweets(context):

    debug_channel = utils.get_bot_commands_channel(context.guild)

    num_tweets = 20
    queue_wrapper.is_populating = True

    while num_tweets != 0:
        try:
            static_data = tweet_data_wrapper.get_static_data(
                client.profile, num_tweets - 1)
            dynamic_data = tweet_data_wrapper.get_dynamic_data()
            await embed_and_send(static_data, dynamic_data)
            await debug_channel.send(
                f"✅ Tweet {num_tweets-1} retrieved and sent successfully.")
        except Exception as e:
            await debug_channel.send(
                f"❌ Tweet {num_tweets-1} retrieved unsuccessfully:\n<{e}>")
        num_tweets -= 1
        await asyncio.sleep(1)

    queue_wrapper.is_populating = False
async def debug_reaction(emoji, channel, member, is_add=True):
    """
    :param emoji: The emoji the user reacted with
    :param channel: The channel the user reacted inside of
    :param member: The member that did the reactiobn
    :return: None

    Ideally, this should only execute if the user
    is reacting under personally designated environment
    (channel compared to emoji) matches.
    """

    bot_channel = utils.get_bot_commands_channel(member.guild)
    owner = utils.get_codebase_owner_member(member.guild)

    if is_add:
        await bot_channel.send(
            f"{owner.mention}, member `{member}` reacted to {emoji} in {channel.mention}"
        )
    else:
        await bot_channel.send(
            f"{owner.mention}, member `{member}` unreacted from {emoji} in {channel.mention}"
        )
Пример #11
0
async def send_game_manager_panel(context):

    """
    :param context: Command context
    :return: None

    Send out the game manager panel.
    """

    await context.message.delete()
    contact_info = utils.get_game_manager_info()
    print(f"Have contact info values?:\n{contact_info.values()}")

    def _a_gm_channel():

        nonlocal contact_info

        if context.channel.name in str(contact_info.values()):  # Had to cast to str
            return True
        return False

    for user_id, info in contact_info.items():

        """
        0 = role titles
        1 = names
        2 = emails
        3 = colors
        4 = userids
        5 = descriptions
        6 = channel names (used for role)
        7 = icon links
        """

        if context.channel.name in contact_info[user_id] or not _a_gm_channel():

            """
            The latter condition will only execute if the current iteration
            is the intended channel the user wanted to type in.
            
            Granted, I could update all channels in one fell swoop, but for
            the sake of responsiveness, I'd rather the user be reassured
            nearly immediately based on their intuition. (It could very well
            take a long time for all channels to be updated, depends on how
            Discord wants to behave in general)
            """

            # Determining description:
            if info[5]:
                description = info[5]
            else:
                role_name = info[6].replace("-", " ").title().replace("Of", "of").replace("Fifa", "FIFA").replace("Csgo", "CS:GO")
                role = discord.utils.get(context.guild.roles, name=role_name)
                role_gm = discord.utils.get(context.guild.roles, name=config['role']['gamemanager'])
                description = f"Looking for the **{role.mention}** **{role_gm.mention}**? Please message me!"

            # Adjusting embed data as usual
            embed = discord.Embed(title=info[1],
                                  description=description,
                                  color=int(info[3], 16))

            member = discord.utils.get(context.message.guild.members, id=int(info[4]))
            embed.set_author(name=info[0],
                             icon_url=info[7])
            embed.set_thumbnail(url=member.avatar_url)
            embed.add_field(name="`Discord Contact:`",
                            value=member.mention,
                            inline=True)
            embed.add_field(name="`Email Contact:`",
                            value=f"**{info[2]}**",
                            inline=True)

            if _a_gm_channel():
                gm_channel = context.channel
            else:
                gm_channel = discord.utils.get(context.guild.channels, name=info[6])

            bot_channel = utils.get_bot_commands_channel(context.guild)
            last_message = await utils.get_last_message_from_channel(gm_channel)
            if last_message:
                await last_message.edit(embed=embed)
                await bot_channel.send(f"✅ Finished editing contact details in {gm_channel.mention} for Game Manager {member.mention}")
            else:
                await context.send(embed=embed)
                await bot_channel.send(f"✅ Finished creating new contact details in {gm_channel.mention} for Game Manager {member.mention}")
Пример #12
0
    async def poll_for_data_from_stream(self, client):
        """
        A workaround for asynchronous function unable to
        be threaded. This is function is called *last* at
        on_ready(). Bot remains operable.

        Reasoning: embeds need to be awaited.
        Listener pipeline is NOT asynchronous,
        which means embed sending can't be
        awaited there.

        This (asynchronous) function polls any data
        that was stored from the pipeline in
        2 second intervals.

        """

        listener.social_media_channel = utils.get_social_media_feed_channel(
            client.guild)
        listener.commands_channel = utils.get_bot_commands_channel(
            client.guild)
        listener.error = None  # Assuming a user does this manually, this needs to clear

        print(f"Polling for stream...")

        await listener.commands_channel.send(f"Started Twitter feed.")
        self.is_polling = True

        while True:
            try:
                await asyncio.sleep(self._poll_rate)
                if listener.static_data and listener.dynamic_data:
                    await embed_and_send(listener.static_data,
                                         listener.dynamic_data)
                    listener.static_data = None
                    listener.dynamic_data = None
                elif listener.error:
                    await listener.commands_channel.send(
                        f"Twitter poll error: `{listener.error}`\n*Unable to update Twitter feed*. Please retry in __15__ minutes, or refer to the Twitter API response codes for more info."
                    )
                    self.is_polling = False
                    break
                else:
                    print(
                        f"No messages in stream listener. Retrying in 5 seconds. Error: {listener.error}"
                    )

                await asyncio.sleep(5)
            except Exception as e:

                if self._num_retries == 0:
                    await listener.commands_channel.send(
                        f"Some unknown exception was caught trying to poll stream. {self._num_retries} retries remaining!\nError: `{e}`"
                    )
                else:
                    await listener.commands_channel.send(
                        f"`{self._num_retries}` remaining...")

                print(
                    f"Some unknown exception caught trying to poll stream, retrying!:\n\n{e}"
                )

                if self._num_retries > 0:
                    self._num_retries -= 1
                    continue
                else:
                    self.is_polling = False
                    listener.error = e
                    owner = discord.utils.get(client.guild.members,
                                              id=int(config['id']['owner']))
                    await listener.commands_channel.send(
                        f"{owner.mention}, unable to start poller after 5 retries. See `!metrics` for more information"
                    )
                    break