diff --git a/leaderboard/leaderboard.py b/leaderboard/leaderboard.py index aaeb978..14de4cc 100644 --- a/leaderboard/leaderboard.py +++ b/leaderboard/leaderboard.py @@ -122,8 +122,8 @@ class Leaderboard(commands.Cog): await self.bot.wait_until_ready() while True: try: - await self._perform_full_sync() - log.info("Completed automatic leaderboard sync") + success_count, fail_count = await self._perform_full_sync() + log.info(f"Completed automatic leaderboard sync: {success_count} successes, {fail_count} failures") await asyncio.sleep(21600) # 6 hours in seconds except asyncio.CancelledError: break @@ -137,27 +137,69 @@ class Leaderboard(commands.Cog): success_count = 0 fail_count = 0 processed_users = set() + users_to_sync = [] + # First, collect all users and their credits for guild in self.bot.guilds: for member in guild.members: if member.bot or member.id in processed_users: continue try: - # Get total credits across all guilds credits = await self.get_user_credits(member) + opted_out = await self.config.user(member).opted_out() - # Update API - if await self._try_api_update(str(member.id), str(member), credits): - success_count += 1 - else: - fail_count += 1 - + # Only include users with sufficient credits or who are opted out + # (we need to sync opted-out status even for users below threshold) + if credits >= 10000 or opted_out: + users_to_sync.append({ + "member": member, + "credits": credits, + "opted_out": opted_out + }) processed_users.add(member.id) except Exception as e: - log.error(f"Error syncing user {member} ({member.id}): {e}") + log.error(f"Error processing user {member} ({member.id}): {e}") fail_count += 1 + # Debug logging + log.info(f"Found {len(users_to_sync)} users to sync") + + # Now perform the sync + for user_data in users_to_sync: + member = user_data["member"] + try: + if await self._try_api_update( + str(member.id), + str(member), + user_data["credits"] + ): + success_count += 1 + log.debug(f"Successfully synced {member} ({member.id})") + else: + fail_count += 1 + log.error(f"Failed to sync {member} ({member.id})") + except Exception as e: + log.error(f"Error syncing user {member} ({member.id}): {e}") + fail_count += 1 + + # Verify the sync by checking the API + try: + async with self.session.get( + f"{self.api_base_url}/leaderboard", + headers={"Authorization": self.admin_secret["admin_secret"]} + ) as resp: + if resp.status == 200: + data = await resp.json() + if "leaderboard" in data: + log.info(f"API verification: {len(data['leaderboard'])} users in leaderboard after sync") + else: + log.error("API verification failed: Invalid response format") + else: + log.error(f"API verification failed: Status {resp.status}") + except Exception as e: + log.error(f"API verification failed: {e}") + return success_count, fail_count async def cog_load(self): @@ -166,38 +208,18 @@ class Leaderboard(commands.Cog): async def get_user_credits(self, user: discord.Member) -> int: """Get a user's total credits from all servers.""" - total_credits = 0 - try: - # Get credits from the user's current server - try: - total_credits = await bank.get_balance(user) - except Exception as e: - log.error(f"Error getting balance for {user} in current guild: {e}") - - # Then add credits from all other servers - for guild in self.bot.guilds: - if guild.id != user.guild.id: # Skip current guild - try: - member = guild.get_member(user.id) - if member: # If user is in this guild - guild_credits = await bank.get_balance(member) - total_credits += guild_credits - except Exception as e: - log.error(f"Error getting bank balance for {user} in {guild}: {e}") - continue - + # Use Red's bank API to get the user's balance + # This automatically handles the global bank if enabled + return await bank.get_balance(user) except Exception as e: - log.error(f"Error getting total credits for {user}: {e}") - - return total_credits + log.error(f"Error getting credits for {user}: {e}") + return 0 async def get_all_balances(self) -> List[dict]: """Get all users' credit balances across all servers.""" all_users = {} min_credits = 10000 # Minimum credits to show on leaderboard - matches API's MIN_CREDITS - - # First get all unique members across all guilds processed_users = set() # Process each guild @@ -215,13 +237,16 @@ class Leaderboard(commands.Cog): continue try: - total_credits = await self.get_user_credits(member) + credits = await self.get_user_credits(member) - if total_credits >= min_credits: + # Debug logging for credit calculation + log.debug(f"Calculated credits for {member} ({member.id}): {credits}") + + if credits >= min_credits: all_users[member.id] = { "userId": str(member.id), "username": str(member), - "points": total_credits + "points": credits } processed_users.add(member.id) @@ -255,6 +280,9 @@ class Leaderboard(commands.Cog): # Get opt-out status opted_out = await self.config.user_from_id(int(user_id)).opted_out() + # Debug logging before update + log.debug(f"Sending API update for {username} ({user_id}): {credits} credits, opted_out: {opted_out}") + async with self.session.post( f"{self.api_base_url}/leaderboard", headers={ @@ -409,7 +437,7 @@ class Leaderboard(commands.Cog): credits = await self.get_user_credits(member) # Debug logging - log.info(f"Credits check for {member}: {credits} credits") + log.info(f"Credits check for {member} ({member.id}): {credits} credits") # Get user's rank leaderboard_data = await self.get_all_balances() @@ -455,7 +483,8 @@ class Leaderboard(commands.Cog): title="🔄 Global Leaderboard Resync Complete", description=( f"Successfully updated: **{success_count}** users\n" - f"Failed to update: **{fail_count}** users" + f"Failed to update: **{fail_count}** users\n\n" + "Note: Updates may take a few moments to appear on the website." ), color=await ctx.embed_color(), timestamp=datetime.now(timezone.utc)