From eba75f73964a258119e16ba2abfc181055281022 Mon Sep 17 00:00:00 2001 From: Janine vN Date: Wed, 1 Dec 2021 22:41:07 -0500 Subject: Add `.aoc link` command This new command will allow people to associate their Discord ID with their Advent of Code name. This Redis Cache idea was taken from the hacktoberfest stats command, which allows people to associate their github username to then pull the correct stats. This does not check if the name exists on the leaderboard and that is intentional. Due to the cooldown on the leaderboard I don't want to rely on that before someone can link their account. Additionally, someone may change their display name on the Advent of Code side and I don't think validation of it existing on the leaderboard gets us anything. The usefulness of this function will not be apparent in this cog, but it is necessary for something fun I'd like to do. --- bot/exts/events/advent_of_code/_cog.py | 69 ++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) (limited to 'bot') diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index af1cbcf5..1b1cd9f8 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -6,6 +6,7 @@ from typing import Optional import arrow import discord +from async_rediscache import RedisCache from discord.ext import commands from bot.bot import Bot @@ -29,6 +30,8 @@ AOC_WHITELIST = AOC_WHITELIST_RESTRICTED + (Channels.advent_of_code,) class AdventOfCode(commands.Cog): """Advent of Code festivities! Ho Ho Ho!""" + account_links = RedisCache() + def __init__(self, bot: Bot): self.bot = bot @@ -172,6 +175,72 @@ class AdventOfCode(commands.Cog): else: await ctx.message.add_reaction(Emojis.envelope) + @in_month(Month.NOVEMBER, Month.DECEMBER) + @adventofcode_group.command( + name="link", + aliases=("connect",), + brief="Tie your Discord account with your Advent of Code name." + ) + @whitelist_override(channels=AOC_WHITELIST) + async def aoc_link_account(self, ctx: commands.Context, aoc_name: str = None) -> None: + """ + Link your Discord Account to your Advent of Code name. + + Stored in a Redis Cache, Discord ID: Advent of Code Name + """ + cache_items = await self.account_links.items() + + # A short circuit in case the cache is empty + if len(cache_items) == 0 and aoc_name: + log.info(f"{ctx.author} ({ctx.author.id}) is now linked to {aoc_name}.") + await self.account_links.set(ctx.author.id, aoc_name) + await ctx.reply(f"You have linked your Discord ID to {aoc_name}.") + return + elif len(cache_items) == 0: + await ctx.reply( + "You have not linked an Advent of Code account." + "Please re-run the command with one specified." + ) + return + + cache_aoc_name = [value for _, value in cache_items] + + if aoc_name: + # Let's check the current values in the cache to make sure it isn't already tied to a different account + if aoc_name == await self.account_links.get(ctx.author.id): + await ctx.reply(f"{aoc_name} is already tied to your account.") + return + elif aoc_name in cache_aoc_name: + log.info( + f"{ctx.author} ({ctx.author.id}) tried to connect their account to {aoc_name}," + " but it's already connected to another user." + ) + await ctx.reply( + f"{aoc_name} is already tied to another account." + " Please contact an admin if you believe this is an error." + ) + return + + # Update an existing link + if old_aoc_name := await self.account_links.get(ctx.author.id): + log.info(f"{ctx.author} ({ctx.author.id}) has changed their link from {old_aoc_name} to {aoc_name}.") + await self.account_links.set(ctx.author.id, aoc_name) + await ctx.reply(f"Your linked account has been changed to {aoc_name}.") + else: + # Create a new link + log.info(f"{ctx.author} ({ctx.author.id}) is now linked to {aoc_name}.") + await self.account_links.set(ctx.author.id, aoc_name) + await ctx.reply(f"You have linked your Discord ID to {aoc_name}.") + else: + # User has not supplied a name, let's check if they're in the cache or not + if cache_name := await self.account_links.get(ctx.author.id): + await ctx.reply(f"You have already linked an Advent of Code account: {cache_name}.") + else: + await ctx.reply( + "You have not linked an Advent of Code account." + " Please re-run the command with one specified." + ) + @in_month(Month.DECEMBER) @adventofcode_group.command( name="dayandstar", -- cgit v1.2.3 From 846c34fd8988eaede08186fa9fb342213dc85585 Mon Sep 17 00:00:00 2001 From: Janine vN Date: Fri, 3 Dec 2021 18:46:39 -0500 Subject: Remove unneeded check and add comments Removes the unneeded check for if the cache is empty. Also adds a seconds comment about the format of the contents of the Redis cache. --- bot/exts/events/advent_of_code/_cog.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) (limited to 'bot') diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 1b1cd9f8..8d87b5bc 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -30,6 +30,7 @@ AOC_WHITELIST = AOC_WHITELIST_RESTRICTED + (Channels.advent_of_code,) class AdventOfCode(commands.Cog): """Advent of Code festivities! Ho Ho Ho!""" + # Redis Cache for linking Discord IDs to Advent of Code usernames account_links = RedisCache() def __init__(self, bot: Bot): @@ -186,23 +187,9 @@ class AdventOfCode(commands.Cog): """ Link your Discord Account to your Advent of Code name. - Stored in a Redis Cache, Discord ID: Advent of Code Name + Stored in a Redis Cache with the format of `Discord ID: Advent of Code Name` """ cache_items = await self.account_links.items() - - # A short circuit in case the cache is empty - if len(cache_items) == 0 and aoc_name: - log.info(f"{ctx.author} ({ctx.author.id}) is now linked to {aoc_name}.") - await self.account_links.set(ctx.author.id, aoc_name) - await ctx.reply(f"You have linked your Discord ID to {aoc_name}.") - return - elif len(cache_items) == 0: - await ctx.reply( - "You have not linked an Advent of Code account." - "Please re-run the command with one specified." - ) - return - cache_aoc_name = [value for _, value in cache_items] if aoc_name: -- cgit v1.2.3 From 1ac965f67fea8e5dd0e0f026aca27e3368f4e44e Mon Sep 17 00:00:00 2001 From: Janine vN Date: Fri, 3 Dec 2021 20:50:17 -0500 Subject: Add unlink AoC command Adds the ability for the user to unlink their advent of code name. It will delete the entry in the cache if it exists. --- bot/exts/events/advent_of_code/_cog.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'bot') diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 8d87b5bc..7f904f6b 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -228,6 +228,27 @@ class AdventOfCode(commands.Cog): " Please re-run the command with one specified." ) + @in_month(Month.NOVEMBER, Month.DECEMBER) + @adventofcode_group.command( + name="unlink", + aliases=("disconnect",), + brief="Tie your Discord account with your Advent of Code name." + ) + @whitelist_override(channels=AOC_WHITELIST) + async def aoc_unlink_account(self, ctx: commands.Context) -> None: + """ + Unlink your Discord ID with your Advent of Code leaderboard name. + + Deletes the entry that was Stored in the Redis cache. + """ + if aoc_cache_name := await self.account_links.get(ctx.author.id): + log.info(f"Unlinking {ctx.author} ({ctx.author.id}) from Advent of Code account {aoc_cache_name}") + await self.account_links.delete(ctx.author.id) + await ctx.reply(f"We have removed the link between your Discord ID and {aoc_cache_name}.") + else: + log.info(f"Attempted to unlink {ctx.author} ({ctx.author.id}), but not link was found.") + await ctx.reply("You don't have an Advent of Code account linked.") + @in_month(Month.DECEMBER) @adventofcode_group.command( name="dayandstar", -- cgit v1.2.3 From 00e3fe5bede6f8310405e143179530df0ad3ca95 Mon Sep 17 00:00:00 2001 From: Janine vN Date: Fri, 3 Dec 2021 20:53:59 -0500 Subject: Adjust wording on log statements to present tense --- bot/exts/events/advent_of_code/_cog.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 7f904f6b..b7d26cb9 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -210,12 +210,12 @@ class AdventOfCode(commands.Cog): # Update an existing link if old_aoc_name := await self.account_links.get(ctx.author.id): - log.info(f"{ctx.author} ({ctx.author.id}) has changed their link from {old_aoc_name} to {aoc_name}.") + log.info(f"Changing link for{ctx.author} ({ctx.author.id}) from {old_aoc_name} to {aoc_name}.") await self.account_links.set(ctx.author.id, aoc_name) await ctx.reply(f"Your linked account has been changed to {aoc_name}.") else: # Create a new link - log.info(f"{ctx.author} ({ctx.author.id}) is now linked to {aoc_name}.") + log.info(f"Linking {ctx.author} ({ctx.author.id}) to account {aoc_name}.") await self.account_links.set(ctx.author.id, aoc_name) await ctx.reply(f"You have linked your Discord ID to {aoc_name}.") else: @@ -246,7 +246,7 @@ class AdventOfCode(commands.Cog): await self.account_links.delete(ctx.author.id) await ctx.reply(f"We have removed the link between your Discord ID and {aoc_cache_name}.") else: - log.info(f"Attempted to unlink {ctx.author} ({ctx.author.id}), but not link was found.") + log.info(f"Attempted to unlink {ctx.author} ({ctx.author.id}), but no link was found.") await ctx.reply("You don't have an Advent of Code account linked.") @in_month(Month.DECEMBER) -- cgit v1.2.3 From b3a7c79ffb1f4220bad8ca3814d594a9b1b00826 Mon Sep 17 00:00:00 2001 From: Janine vN Date: Fri, 3 Dec 2021 21:02:28 -0500 Subject: Make aoc_name a keyword arguemnt to accept spaces Makes `aoc_name` in the link command a keyword only argument. This allows users to link accounts with spaces in the name without having to use quotes. --- bot/exts/events/advent_of_code/_cog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index b7d26cb9..55fd0ac6 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -183,7 +183,7 @@ class AdventOfCode(commands.Cog): brief="Tie your Discord account with your Advent of Code name." ) @whitelist_override(channels=AOC_WHITELIST) - async def aoc_link_account(self, ctx: commands.Context, aoc_name: str = None) -> None: + async def aoc_link_account(self, ctx: commands.Context, *, aoc_name: str = None) -> None: """ Link your Discord Account to your Advent of Code name. -- cgit v1.2.3 From b134010e1682a40d2aa9e3ce893c274388896680 Mon Sep 17 00:00:00 2001 From: Janine vN Date: Fri, 3 Dec 2021 21:29:01 -0500 Subject: Adjust `.aoc lb` to use linked account in cache If the user has not supplied a name to use for the leaderboard, then code will check if they have an account linked. If they do, it will use the linked account in the leaderboard to show placement. --- bot/exts/events/advent_of_code/_cog.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 16176c69..49b604ab 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -311,6 +311,10 @@ class AdventOfCode(commands.Cog): if aoc_name and aoc_name.startswith('"') and aoc_name.endswith('"'): aoc_name = aoc_name[1:-1] + # Check if an advent of code account is linked in the Redis Cache if aoc_name is not given + if (aoc_cache_name := await self.account_links.get(ctx.author.id)) and aoc_name is None: + aoc_name = aoc_cache_name + async with ctx.typing(): try: leaderboard = await _helpers.fetch_leaderboard(self_placement_name=aoc_name) @@ -321,7 +325,7 @@ class AdventOfCode(commands.Cog): number_of_participants = leaderboard["number_of_participants"] top_count = min(AocConfig.leaderboard_displayed_members, number_of_participants) - self_placement_header = "(and your personal stats compared to the top 10)" if aoc_name else "" + self_placement_header = " (and your personal stats compared to the top 10)" if aoc_name else "" header = f"Here's our current top {top_count}{self_placement_header}! {Emojis.christmas_tree * 3}" table = "```\n" \ f"{leaderboard['placement_leaderboard'] if aoc_name else leaderboard['top_leaderboard']}" \ -- cgit v1.2.3 From f4324a0f447a7791743ce9a5c4f0957f32738b78 Mon Sep 17 00:00:00 2001 From: Janine vN Date: Sat, 4 Dec 2021 10:55:49 -0500 Subject: Adjust variable name for clarity and add space --- bot/exts/events/advent_of_code/_cog.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/events/advent_of_code/_cog.py b/bot/exts/events/advent_of_code/_cog.py index 49b604ab..52254ea1 100644 --- a/bot/exts/events/advent_of_code/_cog.py +++ b/bot/exts/events/advent_of_code/_cog.py @@ -193,14 +193,14 @@ class AdventOfCode(commands.Cog): Stored in a Redis Cache with the format of `Discord ID: Advent of Code Name` """ cache_items = await self.account_links.items() - cache_aoc_name = [value for _, value in cache_items] + cache_aoc_names = [value for _, value in cache_items] if aoc_name: # Let's check the current values in the cache to make sure it isn't already tied to a different account if aoc_name == await self.account_links.get(ctx.author.id): await ctx.reply(f"{aoc_name} is already tied to your account.") return - elif aoc_name in cache_aoc_name: + elif aoc_name in cache_aoc_names: log.info( f"{ctx.author} ({ctx.author.id}) tried to connect their account to {aoc_name}," " but it's already connected to another user." @@ -213,7 +213,7 @@ class AdventOfCode(commands.Cog): # Update an existing link if old_aoc_name := await self.account_links.get(ctx.author.id): - log.info(f"Changing link for{ctx.author} ({ctx.author.id}) from {old_aoc_name} to {aoc_name}.") + log.info(f"Changing link for {ctx.author} ({ctx.author.id}) from {old_aoc_name} to {aoc_name}.") await self.account_links.set(ctx.author.id, aoc_name) await ctx.reply(f"Your linked account has been changed to {aoc_name}.") else: -- cgit v1.2.3 From 03b5464e6e37f625ba7a590d45120f4b46b1d0aa Mon Sep 17 00:00:00 2001 From: Janine vN Date: Sat, 4 Dec 2021 11:00:48 -0500 Subject: Add more information to `.aoc lb` error embed Advent of Code Leaderboard BadArgument error embed now mentions to join the leaderboard and to wait up to 30 minutes if you've joined recently. --- bot/exts/events/advent_of_code/_helpers.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'bot') diff --git a/bot/exts/events/advent_of_code/_helpers.py b/bot/exts/events/advent_of_code/_helpers.py index 35258544..807cc275 100644 --- a/bot/exts/events/advent_of_code/_helpers.py +++ b/bot/exts/events/advent_of_code/_helpers.py @@ -216,6 +216,9 @@ def _format_leaderboard(leaderboard: dict[str, dict], self_placement_name: str = if self_placement_name and not self_placement_exists: raise commands.BadArgument( "Sorry, your profile does not exist in this leaderboard." + "\n\n" + "To join our leaderboard, run the command `.aoc join`." + " If you've joined recently, please wait up to 30 minutes for our leaderboard to refresh." ) return "\n".join(leaderboard_lines) -- cgit v1.2.3