diff options
| author | 2019-10-19 10:41:14 -0700 | |
|---|---|---|
| committer | 2019-10-19 10:41:14 -0700 | |
| commit | ba4642b11285faae679dc0b2f160272fc5d87f9c (patch) | |
| tree | c9130f76438853c99ff6db0cde4413dcfdc716c2 /bot | |
| parent | Fixes the changes. (diff) | |
| parent | Merge branch 'master' into monster_bio (diff) | |
Merge branch 'monster_bio' of https://github.com/quizzicaltrains/seasonalbot into monster_bio
Diffstat (limited to 'bot')
| -rw-r--r-- | bot/constants.py | 7 | ||||
| -rw-r--r-- | bot/seasons/christmas/adventofcode.py | 14 | ||||
| -rw-r--r-- | bot/seasons/evergreen/issues.py | 73 | ||||
| -rw-r--r-- | bot/seasons/halloween/hacktoberstats.py | 2 | 
4 files changed, 68 insertions, 28 deletions
| diff --git a/bot/constants.py b/bot/constants.py index 749af1d0..9c4f102c 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -22,6 +22,7 @@ class AdventOfCode:  class Channels(NamedTuple):      admins = 365960823622991872 +    advent_of_code = 517745814039166986      announcements = int(environ.get("CHANNEL_ANNOUNCEMENTS", 354619224620138496))      big_brother_logs = 468507907357409333      bot = 267659945086812160 @@ -87,6 +88,12 @@ class Emojis:      terning5 = "<:terning5:431249716328792064>"      terning6 = "<:terning6:431249726705369098>" +    issue = "<:IssueOpen:629695470327037963>" +    issue_closed = "<:IssueClosed:629695470570307614>" +    pull_request = "<:PROpen:629695470175780875>" +    pull_request_closed = "<:PRClosed:629695470519713818>" +    merge = "<:PRMerged:629695470570176522>" +  class Lovefest:      role_id = int(environ.get("LOVEFEST_ROLE_ID", 542431903886606399)) diff --git a/bot/seasons/christmas/adventofcode.py b/bot/seasons/christmas/adventofcode.py index 513c1020..007e4783 100644 --- a/bot/seasons/christmas/adventofcode.py +++ b/bot/seasons/christmas/adventofcode.py @@ -13,7 +13,7 @@ from bs4 import BeautifulSoup  from discord.ext import commands  from pytz import timezone -from bot.constants import AdventOfCode as AocConfig, Channels, Colours, Emojis, Tokens +from bot.constants import AdventOfCode as AocConfig, Channels, Colours, Emojis, Tokens, WHITELISTED_CHANNELS  from bot.decorators import override_in_channel  log = logging.getLogger(__name__) @@ -24,6 +24,8 @@ AOC_SESSION_COOKIE = {"session": Tokens.aoc_session_cookie}  EST = timezone("EST")  COUNTDOWN_STEP = 60 * 5 +AOC_WHITELIST = WHITELISTED_CHANNELS + (Channels.advent_of_code,) +  def is_in_advent() -> bool:      """Utility function to check if we are between December 1st and December 25th.""" @@ -126,7 +128,7 @@ class AdventOfCode(commands.Cog):          self.status_task = asyncio.ensure_future(self.bot.loop.create_task(status_coro))      @commands.group(name="adventofcode", aliases=("aoc",), invoke_without_command=True) -    @override_in_channel() +    @override_in_channel(AOC_WHITELIST)      async def adventofcode_group(self, ctx: commands.Context) -> None:          """All of the Advent of Code commands."""          await ctx.send_help(ctx.command) @@ -136,6 +138,7 @@ class AdventOfCode(commands.Cog):          aliases=("sub", "notifications", "notify", "notifs"),          brief="Notifications for new days"      ) +    @override_in_channel(AOC_WHITELIST)      async def aoc_subscribe(self, ctx: commands.Context) -> None:          """Assign the role for notifications about new days being ready."""          role = ctx.guild.get_role(AocConfig.role_id) @@ -150,6 +153,7 @@ class AdventOfCode(commands.Cog):                             f"If you don't want them any more, run `{unsubscribe_command}` instead.")      @adventofcode_group.command(name="unsubscribe", aliases=("unsub",), brief="Notifications for new days") +    @override_in_channel(AOC_WHITELIST)      async def aoc_unsubscribe(self, ctx: commands.Context) -> None:          """Remove the role for notifications about new days being ready."""          role = ctx.guild.get_role(AocConfig.role_id) @@ -161,6 +165,7 @@ class AdventOfCode(commands.Cog):              await ctx.send("Hey, you don't even get any notifications about new Advent of Code tasks currently anyway.")      @adventofcode_group.command(name="countdown", aliases=("count", "c"), brief="Return time left until next day") +    @override_in_channel(AOC_WHITELIST)      async def aoc_countdown(self, ctx: commands.Context) -> None:          """Return time left until next day."""          if not is_in_advent(): @@ -178,11 +183,13 @@ class AdventOfCode(commands.Cog):          await ctx.send(f"There are {hours} hours and {minutes} minutes left until day {tomorrow.day}.")      @adventofcode_group.command(name="about", aliases=("ab", "info"), brief="Learn about Advent of Code") +    @override_in_channel(AOC_WHITELIST)      async def about_aoc(self, ctx: commands.Context) -> None:          """Respond with an explanation of all things Advent of Code."""          await ctx.send("", embed=self.cached_about_aoc)      @adventofcode_group.command(name="join", aliases=("j",), brief="Learn how to join PyDis' private AoC leaderboard") +    @override_in_channel(AOC_WHITELIST)      async def join_leaderboard(self, ctx: commands.Context) -> None:          """DM the user the information for joining the PyDis AoC private leaderboard."""          author = ctx.message.author @@ -203,6 +210,7 @@ class AdventOfCode(commands.Cog):          aliases=("board", "lb"),          brief="Get a snapshot of the PyDis private AoC leaderboard",      ) +    @override_in_channel(AOC_WHITELIST)      async def aoc_leaderboard(self, ctx: commands.Context, number_of_people_to_display: int = 10) -> None:          """          Pull the top number_of_people_to_display members from the PyDis leaderboard and post an embed. @@ -244,6 +252,7 @@ class AdventOfCode(commands.Cog):          aliases=("dailystats", "ds"),          brief="Get daily statistics for the PyDis private leaderboard"      ) +    @override_in_channel(AOC_WHITELIST)      async def private_leaderboard_daily_stats(self, ctx: commands.Context) -> None:          """          Respond with a table of the daily completion statistics for the PyDis private leaderboard. @@ -287,6 +296,7 @@ class AdventOfCode(commands.Cog):          aliases=("globalboard", "gb"),          brief="Get a snapshot of the global AoC leaderboard",      ) +    @override_in_channel(AOC_WHITELIST)      async def global_leaderboard(self, ctx: commands.Context, number_of_people_to_display: int = 10) -> None:          """          Pull the top number_of_people_to_display members from the global AoC leaderboard and post an embed. diff --git a/bot/seasons/evergreen/issues.py b/bot/seasons/evergreen/issues.py index 438ab475..c7501a5d 100644 --- a/bot/seasons/evergreen/issues.py +++ b/bot/seasons/evergreen/issues.py @@ -3,10 +3,16 @@ import logging  import discord  from discord.ext import commands -from bot.constants import Colours +from bot.constants import Channels, Colours, Emojis, WHITELISTED_CHANNELS  from bot.decorators import override_in_channel  log = logging.getLogger(__name__) +ISSUE_WHITELIST = WHITELISTED_CHANNELS + (Channels.seasonalbot_chat,) + +BAD_RESPONSE = { +    404: "Issue/pull request not located! Please enter a valid number!", +    403: "Rate limit has been hit! Please try again later!" +}  class Issues(commands.Cog): @@ -15,43 +21,58 @@ class Issues(commands.Cog):      def __init__(self, bot: commands.Bot):          self.bot = bot -    @commands.command(aliases=("issues",)) -    @override_in_channel() +    @commands.command(aliases=("pr",)) +    @override_in_channel(ISSUE_WHITELIST)      async def issue(          self, ctx: commands.Context, number: int, repository: str = "seasonalbot", user: str = "python-discord"      ) -> None:          """Command to retrieve issues from a GitHub repository.""" -        api_url = f"https://api.github.com/repos/{user}/{repository}/issues/{number}" -        failed_status = { -            404: f"Issue #{number} doesn't exist in the repository {user}/{repository}.", -            403: f"Rate limit exceeded. Please wait a while before trying again!" -        } +        url = f"https://api.github.com/repos/{user}/{repository}/issues/{number}" +        merge_url = f"https://api.github.com/repos/{user}/{repository}/pulls/{number}/merge" -        async with self.bot.http_session.get(api_url) as r: +        log.trace(f"Querying GH issues API: {url}") +        async with self.bot.http_session.get(url) as r:              json_data = await r.json() -            response_code = r.status - -        if response_code in failed_status: -            return await ctx.send(failed_status[response_code]) -        repo_url = f"https://github.com/{user}/{repository}" -        issue_embed = discord.Embed(colour=Colours.bright_green) -        issue_embed.add_field(name="Repository", value=f"[{user}/{repository}]({repo_url})", inline=False) -        issue_embed.add_field(name="Issue Number", value=f"#{number}", inline=False) -        issue_embed.add_field(name="Status", value=json_data["state"].title()) -        issue_embed.add_field(name="Link", value=json_data["html_url"], inline=False) +        if r.status in BAD_RESPONSE: +            log.warning(f"Received response {r.status} from: {url}") +            return await ctx.send(f"[{str(r.status)}] {BAD_RESPONSE.get(r.status)}") -        description = json_data["body"] -        if len(description) > 1024: -            placeholder = " [...]" -            description = f"{description[:1024 - len(placeholder)]}{placeholder}" +        # The initial API request is made to the issues API endpoint, which will return information +        # if the issue or PR is present. However, the scope of information returned for PRs differs +        # from issues: if the 'issues' key is present in the response then we can pull the data we +        # need from the initial API call. +        if "issues" in json_data.get("html_url"): +            if json_data.get("state") == "open": +                icon_url = Emojis.issue +            else: +                icon_url = Emojis.issue_closed -        issue_embed.add_field(name="Description", value=description, inline=False) +        # If the 'issues' key is not contained in the API response and there is no error code, then +        # we know that a PR has been requested and a call to the pulls API endpoint is necessary +        # to get the desired information for the PR. +        else: +            log.trace(f"PR provided, querying GH pulls API for additional information: {merge_url}") +            async with self.bot.http_session.get(merge_url) as m: +                if json_data.get("state") == "open": +                    icon_url = Emojis.pull_request +                # When the status is 204 this means that the state of the PR is merged +                elif m.status == 204: +                    icon_url = Emojis.merge +                else: +                    icon_url = Emojis.pull_request_closed -        await ctx.send(embed=issue_embed) +        issue_url = json_data.get("html_url") +        description_text = f"[{repository}] #{number} {json_data.get('title')}" +        resp = discord.Embed( +            colour=Colours.bright_green, +            description=f"{icon_url} [{description_text}]({issue_url})" +        ) +        resp.set_author(name="GitHub", url=issue_url) +        await ctx.send(embed=resp)  def setup(bot: commands.Bot) -> None: -    """Github Issues Cog Load.""" +    """Cog Retrieves Issues From Github."""      bot.add_cog(Issues(bot))      log.info("Issues cog loaded") diff --git a/bot/seasons/halloween/hacktoberstats.py b/bot/seasons/halloween/hacktoberstats.py index 9ad44e3f..ab8d865c 100644 --- a/bot/seasons/halloween/hacktoberstats.py +++ b/bot/seasons/halloween/hacktoberstats.py @@ -58,6 +58,7 @@ class HacktoberStats(commands.Cog):          await self.get_stats(ctx, github_username)      @hacktoberstats_group.command(name="link") +    @override_in_channel(HACKTOBER_WHITELIST)      async def link_user(self, ctx: commands.Context, github_username: str = None) -> None:          """          Link the invoking user's Github github_username to their Discord ID. @@ -91,6 +92,7 @@ class HacktoberStats(commands.Cog):              await ctx.send(f"{author_mention}, a GitHub username is required to link your account")      @hacktoberstats_group.command(name="unlink") +    @override_in_channel(HACKTOBER_WHITELIST)      async def unlink_user(self, ctx: commands.Context) -> None:          """Remove the invoking user's account link from the log."""          author_id, author_mention = HacktoberStats._author_mention_from_context(ctx) | 
