Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions bot/exts/advent_of_code/_cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,28 +385,49 @@ async def aoc_leaderboard(self, ctx: commands.Context, *, aoc_name: str | None =
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
is_explict_name: bool = bool(aoc_name)
if (aoc_cache_name := await _caches.account_links.get(ctx.author.id)) and aoc_name is None:
aoc_name = aoc_cache_name

name_not_found: bool = False
async with ctx.typing():
try:
leaderboard = await _helpers.fetch_leaderboard(self_placement_name=aoc_name)
try:
leaderboard = await _helpers.fetch_leaderboard(
self_placement_name=aoc_name, use_you_for_placement=not is_explict_name
)
except _helpers.UserNotInLeaderboardError:
if is_explict_name:
raise commands.BadArgument("Sorry, the provided profile does not exist in this leaderboard.")
aoc_name = None
name_not_found = True
leaderboard = await _helpers.fetch_leaderboard()
except _helpers.FetchingLeaderboardFailedError:
await ctx.send(":x: Unable to fetch leaderboard!")
return

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 ""
header = f"Here's our current top {top_count}{self_placement_header}! {Emojis.christmas_tree * 3}"
header = ""
if name_not_found:
header += (
f"\n:x: Your linked Advent of Code account '{aoc_cache_name}' was not found in the leaderboard."
" Showing top leaderboard only. "
"Wait up to 30 minutes after joining the leaderboard for your stats to appear.\n\n"
)
header += f"Here's our current top {top_count}"
if aoc_name:
header += (
f" (and {'the requested user (\U0001f536)' if is_explict_name else 'your'}"
" personal stats compared to the top 10)"
)
header += f"! {Emojis.christmas_tree * 3}"
table = (
"```\n"
f"{leaderboard['placement_leaderboard'] if aoc_name else leaderboard['top_leaderboard']}"
"\n```"
f"```\n{leaderboard['placement_leaderboard'] if aoc_name else leaderboard['top_leaderboard']} \n```"
)
info_embed = _helpers.get_summary_embed(leaderboard)

info_embed = _helpers.get_summary_embed(leaderboard)
await ctx.send(content=f"{header}\n\n{table}", embed=info_embed)
return

Expand Down
42 changes: 29 additions & 13 deletions bot/exts/advent_of_code/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import aiohttp
import arrow
import discord
from discord.ext import commands
from pydis_core.utils import logging, paste_service

import bot
Expand Down Expand Up @@ -69,6 +68,10 @@ class FetchingLeaderboardFailedError(Exception):
"""Raised when one or more leaderboards could not be fetched at all."""


class UserNotInLeaderboardError(Exception):
"""Raised when a user is not found in the requested leaderboard."""


def leaderboard_sorting_function(entry: tuple[str, dict]) -> tuple[int, int]:
"""
Provide a sorting value for our leaderboard.
Expand Down Expand Up @@ -159,20 +162,29 @@ def _parse_raw_leaderboard_data(raw_leaderboard_data: dict) -> dict:
return {"daily_stats": daily_stats, "leaderboard": sorted_leaderboard, "per_day_and_star": per_day_star_stats}


def _format_leaderboard(leaderboard: dict[str, dict], self_placement_name: str | None = None) -> str:
def _format_leaderboard(
leaderboard: dict[str, dict],
self_placement_name: str | None = None,
*,
use_you_for_placement: bool = True,
) -> str:
"""Format the leaderboard using the AOC_TABLE_TEMPLATE."""
leaderboard_lines = [HEADER]
self_placement_exists = False
for rank, data in enumerate(leaderboard.values(), start=1):
if self_placement_name and data["name"].lower() == self_placement_name.lower():
if use_you_for_placement:
name = f"(You) {data['name']}"
else:
name = f"(\U0001f536) {data['name']}"
leaderboard_lines.insert(
1,
AOC_TABLE_TEMPLATE.format(
rank=rank,
name=f"(You) {data['name']}",
name=name,
score=str(data["score"]),
stars=f"({data['star_1']}, {data['star_2']})"
)
stars=f"({data['star_1']}, {data['star_2']})",
),
)
self_placement_exists = True
continue
Expand All @@ -185,12 +197,7 @@ 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."
)
raise UserNotInLeaderboardError
return "\n".join(leaderboard_lines)


Expand Down Expand Up @@ -285,7 +292,12 @@ def _get_top_leaderboard(full_leaderboard: str) -> str:


@_caches.leaderboard_cache.atomic_transaction
async def fetch_leaderboard(invalidate_cache: bool = False, self_placement_name: str | None = None) -> dict:
async def fetch_leaderboard(
invalidate_cache: bool = False,
self_placement_name: str | None = None,
*,
use_you_for_placement: bool = True,
) -> dict:
"""
Get the current Python Discord combined leaderboard.

Expand Down Expand Up @@ -337,7 +349,11 @@ async def fetch_leaderboard(invalidate_cache: bool = False, self_placement_name:
json.loads(cached_leaderboard["placement_leaderboard"])
)["leaderboard"]
cached_leaderboard["placement_leaderboard"] = _get_top_leaderboard(
_format_leaderboard(formatted_placement_leaderboard, self_placement_name=self_placement_name)
_format_leaderboard(
formatted_placement_leaderboard,
self_placement_name=self_placement_name,
use_you_for_placement=use_you_for_placement,
)
)
return cached_leaderboard

Expand Down