aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar gustavwilliam <[email protected]>2020-10-02 17:08:38 +0200
committerGravatar GitHub <[email protected]>2020-10-02 17:08:38 +0200
commit427821dfd5c272bfd8b42fab630661be2df27ee8 (patch)
tree3b25d4e94caf908201d685c8c3a1298bb4822006
parentlinting smh (diff)
parentAuthenticate GitHub API requests for the Hacktoberfest issue finder. (diff)
Merge branch 'master' into master
-rw-r--r--bot/constants.py7
-rw-r--r--bot/exts/halloween/hacktober-issue-finder.py12
-rw-r--r--bot/exts/halloween/hacktoberstats.py39
-rw-r--r--bot/exts/halloween/spookysound.py48
-rw-r--r--bot/exts/halloween/timeleft.py32
5 files changed, 58 insertions, 80 deletions
diff --git a/bot/constants.py b/bot/constants.py
index 935b90e0..7ec8ac27 100644
--- a/bot/constants.py
+++ b/bot/constants.py
@@ -11,7 +11,6 @@ __all__ = (
"Client",
"Colours",
"Emojis",
- "Hacktoberfest",
"Icons",
"Lovefest",
"Month",
@@ -75,7 +74,7 @@ class Channels(NamedTuple):
python_discussion = 267624335836053506
show_your_projects = int(environ.get("CHANNEL_SHOW_YOUR_PROJECTS", 303934982764625920))
show_your_projects_discussion = 360148304664723466
- hacktoberfest_2019 = 628184417646411776
+ hacktoberfest_2020 = 760857070781071431
class Client(NamedTuple):
@@ -129,10 +128,6 @@ class Emojis:
status_offline = "<:status_offline:470326266537705472>"
-class Hacktoberfest(NamedTuple):
- voice_id = 514420006474219521
-
-
class Icons:
questionmark = "https://cdn.discordapp.com/emojis/512367613339369475.png"
bookmark = (
diff --git a/bot/exts/halloween/hacktober-issue-finder.py b/bot/exts/halloween/hacktober-issue-finder.py
index b5ad1c4f..78acf391 100644
--- a/bot/exts/halloween/hacktober-issue-finder.py
+++ b/bot/exts/halloween/hacktober-issue-finder.py
@@ -7,13 +7,19 @@ import aiohttp
import discord
from discord.ext import commands
-from bot.constants import Month
+from bot.constants import Month, Tokens
from bot.utils.decorators import in_month
log = logging.getLogger(__name__)
URL = "https://api.github.com/search/issues?per_page=100&q=is:issue+label:hacktoberfest+language:python+state:open"
-HEADERS = {"Accept": "application / vnd.github.v3 + json"}
+
+REQUEST_HEADERS = {
+ "User-Agent": "Python Discord Hacktoberbot",
+ "Accept": "application / vnd.github.v3 + json"
+}
+if GITHUB_TOKEN := Tokens.github:
+ REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}"
class HacktoberIssues(commands.Cog):
@@ -66,7 +72,7 @@ class HacktoberIssues(commands.Cog):
url += f"&page={page}"
log.debug(f"making api request to url: {url}")
- async with session.get(url, headers=HEADERS) as response:
+ async with session.get(url, headers=REQUEST_HEADERS) as response:
if response.status != 200:
log.error(f"expected 200 status (got {response.status}) from the GitHub api.")
await ctx.send(f"ERROR: expected 200 status (got {response.status}) from the GitHub api.")
diff --git a/bot/exts/halloween/hacktoberstats.py b/bot/exts/halloween/hacktoberstats.py
index db5e37f2..ed1755e3 100644
--- a/bot/exts/halloween/hacktoberstats.py
+++ b/bot/exts/halloween/hacktoberstats.py
@@ -10,7 +10,7 @@ import aiohttp
import discord
from discord.ext import commands
-from bot.constants import Channels, Month, WHITELISTED_CHANNELS
+from bot.constants import Channels, Month, Tokens, WHITELISTED_CHANNELS
from bot.utils.decorators import in_month, override_in_channel
from bot.utils.persist import make_persistent
@@ -18,7 +18,16 @@ log = logging.getLogger(__name__)
CURRENT_YEAR = datetime.now().year # Used to construct GH API query
PRS_FOR_SHIRT = 4 # Minimum number of PRs before a shirt is awarded
-HACKTOBER_WHITELIST = WHITELISTED_CHANNELS + (Channels.hacktoberfest_2019,)
+HACKTOBER_WHITELIST = WHITELISTED_CHANNELS + (Channels.hacktoberfest_2020,)
+
+REQUEST_HEADERS = {"User-Agent": "Python Discord Hacktoberbot"}
+if GITHUB_TOKEN := Tokens.github:
+ REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}"
+
+GITHUB_NONEXISTENT_USER_MESSAGE = (
+ "The listed users cannot be searched either because the users do not exist "
+ "or you do not have permission to view the users."
+)
class HacktoberStats(commands.Cog):
@@ -29,7 +38,7 @@ class HacktoberStats(commands.Cog):
self.link_json = make_persistent(Path("bot", "resources", "halloween", "github_links.json"))
self.linked_accounts = self.load_linked_users()
- @in_month(Month.OCTOBER)
+ @in_month(Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER)
@commands.group(name="hacktoberstats", aliases=("hackstats",), invoke_without_command=True)
@override_in_channel(HACKTOBER_WHITELIST)
async def hacktoberstats_group(self, ctx: commands.Context, github_username: str = None) -> None:
@@ -57,7 +66,7 @@ class HacktoberStats(commands.Cog):
await self.get_stats(ctx, github_username)
- @in_month(Month.OCTOBER)
+ @in_month(Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER)
@hacktoberstats_group.command(name="link")
@override_in_channel(HACKTOBER_WHITELIST)
async def link_user(self, ctx: commands.Context, github_username: str = None) -> None:
@@ -92,7 +101,7 @@ class HacktoberStats(commands.Cog):
logging.info(f"{author_id} tried to link a GitHub account but didn't provide a username")
await ctx.send(f"{author_mention}, a GitHub username is required to link your account")
- @in_month(Month.OCTOBER)
+ @in_month(Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER)
@hacktoberstats_group.command(name="unlink")
@override_in_channel(HACKTOBER_WHITELIST)
async def unlink_user(self, ctx: commands.Context) -> None:
@@ -175,11 +184,11 @@ class HacktoberStats(commands.Cog):
n = pr_stats['n_prs']
if n >= PRS_FOR_SHIRT:
- shirtstr = f"**{github_username} has earned a tshirt!**"
+ shirtstr = f"**{github_username} has earned a T-shirt or a tree!**"
elif n == PRS_FOR_SHIRT - 1:
- shirtstr = f"**{github_username} is 1 PR away from a tshirt!**"
+ shirtstr = f"**{github_username} is 1 PR away from a T-shirt or a tree!**"
else:
- shirtstr = f"**{github_username} is {PRS_FOR_SHIRT - n} PRs away from a tshirt!**"
+ shirtstr = f"**{github_username} is {PRS_FOR_SHIRT - n} PRs away from a T-shirt or a tree!**"
stats_embed = discord.Embed(
title=f"{github_username}'s Hacktoberfest",
@@ -196,7 +205,7 @@ class HacktoberStats(commands.Cog):
stats_embed.set_author(
name="Hacktoberfest",
url="https://hacktoberfest.digitalocean.com",
- icon_url="https://hacktoberfest.digitalocean.com/pretty_logo.png"
+ icon_url="https://avatars1.githubusercontent.com/u/35706162?s=200&v=4"
)
stats_embed.add_field(
name="Top 5 Repositories:",
@@ -242,16 +251,22 @@ class HacktoberStats(commands.Cog):
f"&per_page={per_page}"
)
- headers = {"user-agent": "Discord Python Hacktoberbot"}
async with aiohttp.ClientSession() as session:
- async with session.get(query_url, headers=headers) as resp:
+ async with session.get(query_url, headers=REQUEST_HEADERS) as resp:
jsonresp = await resp.json()
if "message" in jsonresp.keys():
# One of the parameters is invalid, short circuit for now
api_message = jsonresp["errors"][0]["message"]
- logging.error(f"GitHub API request for '{github_username}' failed with message: {api_message}")
+
+ # Ignore logging non-existent users or users we do not have permission to see
+ if api_message == GITHUB_NONEXISTENT_USER_MESSAGE:
+ logging.debug(f"No GitHub user found named '{github_username}'")
+ else:
+ logging.error(f"GitHub API request for '{github_username}' failed with message: {api_message}")
+
return
+
else:
if jsonresp["total_count"] == 0:
# Short circuit if there aren't any PRs
diff --git a/bot/exts/halloween/spookysound.py b/bot/exts/halloween/spookysound.py
deleted file mode 100644
index 569a9153..00000000
--- a/bot/exts/halloween/spookysound.py
+++ /dev/null
@@ -1,48 +0,0 @@
-import logging
-import random
-from pathlib import Path
-
-import discord
-from discord.ext import commands
-
-from bot.bot import SeasonalBot
-from bot.constants import Hacktoberfest
-
-log = logging.getLogger(__name__)
-
-
-class SpookySound(commands.Cog):
- """A cog that plays a spooky sound in a voice channel on command."""
-
- def __init__(self, bot: SeasonalBot):
- self.bot = bot
- self.sound_files = list(Path("bot/resources/halloween/spookysounds").glob("*.mp3"))
- self.channel = None
-
- @commands.cooldown(rate=1, per=1)
- @commands.command(brief="Play a spooky sound, restricted to once per 2 mins")
- async def spookysound(self, ctx: commands.Context) -> None:
- """
- Connect to the Hacktoberbot voice channel, play a random spooky sound, then disconnect.
-
- Cannot be used more than once in 2 minutes.
- """
- if not self.channel:
- await self.bot.wait_until_guild_available()
- self.channel = self.bot.get_channel(Hacktoberfest.voice_id)
-
- await ctx.send("Initiating spooky sound...")
- file_path = random.choice(self.sound_files)
- src = discord.FFmpegPCMAudio(str(file_path.resolve()))
- voice = await self.channel.connect()
- voice.play(src, after=lambda e: self.bot.loop.create_task(self.disconnect(voice)))
-
- @staticmethod
- async def disconnect(voice: discord.VoiceClient) -> None:
- """Helper method to disconnect a given voice client."""
- await voice.disconnect()
-
-
-def setup(bot: SeasonalBot) -> None:
- """Spooky sound Cog load."""
- bot.add_cog(SpookySound(bot))
diff --git a/bot/exts/halloween/timeleft.py b/bot/exts/halloween/timeleft.py
index 295acc89..47adb09b 100644
--- a/bot/exts/halloween/timeleft.py
+++ b/bot/exts/halloween/timeleft.py
@@ -13,20 +13,23 @@ class TimeLeft(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
- @staticmethod
- def in_october() -> bool:
- """Return True if the current month is October."""
- return datetime.utcnow().month == 10
+ def in_hacktober(self) -> bool:
+ """Return True if the current time is within Hacktoberfest."""
+ _, end, start = self.load_date()
+
+ now = datetime.utcnow()
+
+ return start <= now <= end
@staticmethod
- def load_date() -> Tuple[int, datetime, datetime]:
+ def load_date() -> Tuple[datetime, datetime, datetime]:
"""Return of a tuple of the current time and the end and start times of the next October."""
now = datetime.utcnow()
year = now.year
if now.month > 10:
year += 1
- end = datetime(year, 11, 1, 11, 59, 59)
- start = datetime(year, 10, 1)
+ end = datetime(year, 11, 1, 12) # November 1st 12:00 (UTC-12:00)
+ start = datetime(year, 9, 30, 10) # September 30th 10:00 (UTC+14:00)
return now, end, start
@commands.command()
@@ -35,16 +38,23 @@ class TimeLeft(commands.Cog):
Calculates the time left until the end of Hacktober.
Whilst in October, displays the days, hours and minutes left.
- Only displays the days left until the beginning and end whilst in a different month
+ Only displays the days left until the beginning and end whilst in a different month.
+
+ This factors in that Hacktoberfest starts when it is October anywhere in the world
+ and ends with the same rules. It treats the start as UTC+14:00 and the end as
+ UTC-12.
"""
now, end, start = self.load_date()
diff = end - now
days, seconds = diff.days, diff.seconds
- if self.in_october():
+ if self.in_hacktober():
minutes = seconds // 60
hours, minutes = divmod(minutes, 60)
- await ctx.send(f"There is currently only {days} days, {hours} hours and {minutes}"
- "minutes left until the end of Hacktober.")
+
+ await ctx.send(
+ f"There are {days} days, {hours} hours and {minutes}"
+ f" minutes left until the end of Hacktober."
+ )
else:
start_diff = start - now
start_days = start_diff.days