Refine leaderboard sync process in Leaderboard cog to focus on users with 10,000+ credits. Update logging for clarity on sync results and user credit checks. Enhance error handling and ensure accurate data aggregation while maintaining detailed debug information for better tracking of user states.
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run

This commit is contained in:
Valerie 2025-05-26 06:10:33 -04:00
parent 7eddd891bc
commit deaa1aabb8

View file

@ -123,7 +123,7 @@ class Leaderboard(commands.Cog):
while True: while True:
try: try:
success_count, fail_count = await self._perform_full_sync() success_count, fail_count = await self._perform_full_sync()
log.info(f"Completed automatic leaderboard sync: {success_count} successes, {fail_count} failures") log.info(f"Completed automatic leaderboard sync: {success_count} users with 10,000+ credits synced, {fail_count} failures")
await asyncio.sleep(21600) # 6 hours in seconds await asyncio.sleep(21600) # 6 hours in seconds
except asyncio.CancelledError: except asyncio.CancelledError:
break break
@ -138,8 +138,9 @@ class Leaderboard(commands.Cog):
fail_count = 0 fail_count = 0
processed_users = set() processed_users = set()
users_to_sync = [] users_to_sync = []
min_credits = 10000 # Minimum credits to show on leaderboard
# First, collect all users and their credits # First, collect all eligible users and their credits
for guild in self.bot.guilds: for guild in self.bot.guilds:
for member in guild.members: for member in guild.members:
if member.bot or member.id in processed_users: if member.bot or member.id in processed_users:
@ -147,25 +148,24 @@ class Leaderboard(commands.Cog):
try: try:
credits = await self.get_user_credits(member) credits = await self.get_user_credits(member)
opted_out = await self.config.user(member).opted_out()
# Only include users with sufficient credits or who are opted out # Only sync users with 10,000+ credits
# (we need to sync opted-out status even for users below threshold) if credits >= min_credits:
if credits >= 10000 or opted_out:
users_to_sync.append({ users_to_sync.append({
"member": member, "member": member,
"credits": credits, "credits": credits
"opted_out": opted_out
}) })
log.debug(f"Queued for sync: {member} ({member.id}) with {credits} credits")
processed_users.add(member.id) processed_users.add(member.id)
except Exception as e: except Exception as e:
log.error(f"Error processing user {member} ({member.id}): {e}") log.error(f"Error processing user {member} ({member.id}): {e}")
fail_count += 1 fail_count += 1
# Debug logging # Debug logging
log.info(f"Found {len(users_to_sync)} users to sync") log.info(f"Found {len(users_to_sync)} users with {min_credits}+ credits to sync")
# Now perform the sync # Now perform the sync for eligible users
for user_data in users_to_sync: for user_data in users_to_sync:
member = user_data["member"] member = user_data["member"]
try: try:
@ -175,7 +175,7 @@ class Leaderboard(commands.Cog):
user_data["credits"] user_data["credits"]
): ):
success_count += 1 success_count += 1
log.debug(f"Successfully synced {member} ({member.id})") log.debug(f"Successfully synced {member} ({member.id}) with {user_data['credits']} credits")
else: else:
fail_count += 1 fail_count += 1
log.error(f"Failed to sync {member} ({member.id})") log.error(f"Failed to sync {member} ({member.id})")
@ -193,6 +193,8 @@ class Leaderboard(commands.Cog):
data = await resp.json() data = await resp.json()
if "leaderboard" in data: if "leaderboard" in data:
log.info(f"API verification: {len(data['leaderboard'])} users in leaderboard after sync") log.info(f"API verification: {len(data['leaderboard'])} users in leaderboard after sync")
if len(data['leaderboard']) != len(users_to_sync):
log.warning(f"Mismatch in user count: {len(users_to_sync)} synced vs {len(data['leaderboard'])} in API")
else: else:
log.error("API verification failed: Invalid response format") log.error("API verification failed: Invalid response format")
else: else:
@ -211,7 +213,9 @@ class Leaderboard(commands.Cog):
try: try:
# Use Red's bank API to get the user's balance # Use Red's bank API to get the user's balance
# This automatically handles the global bank if enabled # This automatically handles the global bank if enabled
return await bank.get_balance(user) balance = await bank.get_balance(user)
log.debug(f"Got balance for {user} ({user.id}): {balance} credits")
return balance
except Exception as e: except Exception as e:
log.error(f"Error getting credits for {user}: {e}") log.error(f"Error getting credits for {user}: {e}")
return 0 return 0
@ -240,32 +244,41 @@ class Leaderboard(commands.Cog):
credits = await self.get_user_credits(member) credits = await self.get_user_credits(member)
# Debug logging for credit calculation # Debug logging for credit calculation
log.debug(f"Calculated credits for {member} ({member.id}): {credits}") log.debug(f"Checking credits for {member} ({member.id}): {credits} credits, minimum: {min_credits}")
if credits >= min_credits: # Store user data regardless of credits amount
all_users[member.id] = { all_users[member.id] = {
"userId": str(member.id), "userId": str(member.id),
"username": str(member), "username": str(member),
"points": credits "points": credits
} }
processed_users.add(member.id) processed_users.add(member.id)
except Exception as e: except Exception as e:
log.error(f"Error getting balance for {member}: {e}") log.error(f"Error getting balance for {member}: {e}")
continue continue
# Sort by total credits # Filter and sort users after collecting all data
qualified_users = [
user for user in all_users.values()
if user["points"] >= min_credits
]
sorted_users = sorted( sorted_users = sorted(
all_users.values(), qualified_users,
key=lambda x: x["points"], key=lambda x: x["points"],
reverse=True reverse=True
) )
# Debug logging # Debug logging
log.info(f"Found {len(sorted_users)} users with {min_credits}+ credits") log.info(f"Found {len(all_users)} total users, {len(sorted_users)} with {min_credits}+ credits")
for user in sorted_users[:10]: # Log top 10 for debugging if sorted_users:
log.info(f"User {user['username']} has {user['points']} credits") log.info("Top 10 users:")
for user in sorted_users[:10]:
log.info(f"User {user['username']} ({user['userId']}) has {user['points']} credits")
else:
log.warning("No users found with sufficient credits!")
return sorted_users return sorted_users
async def _try_api_update(self, user_id: str, username: str, credits: int) -> bool: async def _try_api_update(self, user_id: str, username: str, credits: int) -> bool:
@ -349,6 +362,8 @@ class Leaderboard(commands.Cog):
leaderboard_data = await self.get_all_balances() leaderboard_data = await self.get_all_balances()
if not leaderboard_data: if not leaderboard_data:
# Debug info in log
log.warning(f"No leaderboard data returned for guild {ctx.guild.id}")
return await ctx.send("No users have 10,000 or more credits!") return await ctx.send("No users have 10,000 or more credits!")
items_per_page = 10 items_per_page = 10
@ -468,13 +483,13 @@ class Leaderboard(commands.Cog):
@globalboard.command(name="resync") @globalboard.command(name="resync")
@commands.is_owner() @commands.is_owner()
async def resync_leaderboard(self, ctx: commands.Context): async def resync_leaderboard(self, ctx: commands.Context):
"""Force a resync of all users' credits with the API (if configured).""" """Force a resync of all users with 10,000+ credits to the API."""
if not self.session or not self.admin_secret or not self.admin_secret.get("admin_secret"): if not self.session or not self.admin_secret or not self.admin_secret.get("admin_secret"):
await ctx.send("API is not configured.") await ctx.send("API is not configured.")
return return
async with ctx.typing(): async with ctx.typing():
message = await ctx.send("🔄 Starting global leaderboard resync...") message = await ctx.send("🔄 Starting global leaderboard resync (10,000+ credits only)...")
try: try:
success_count, fail_count = await self._perform_full_sync() success_count, fail_count = await self._perform_full_sync()
@ -482,7 +497,7 @@ class Leaderboard(commands.Cog):
embed = discord.Embed( embed = discord.Embed(
title="🔄 Global Leaderboard Resync Complete", title="🔄 Global Leaderboard Resync Complete",
description=( description=(
f"Successfully updated: **{success_count}** users\n" f"Successfully updated: **{success_count}** users with 10,000+ credits\n"
f"Failed to update: **{fail_count}** users\n\n" f"Failed to update: **{fail_count}** users\n\n"
"Note: Updates may take a few moments to appear on the website." "Note: Updates may take a few moments to appear on the website."
), ),