aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/constants.py7
-rw-r--r--bot/seasons/christmas/adventofcode.py14
-rw-r--r--bot/seasons/evergreen/issues.py73
-rw-r--r--bot/seasons/halloween/hacktoberstats.py2
4 files changed, 68 insertions, 28 deletions
diff --git a/bot/constants.py b/bot/constants.py
index 0d4321c8..aa5c3db3 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
@@ -86,6 +87,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)