Implement API connection testing and enhance user credit retrieval in Leaderboard cog
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run

Add a test for the API connection during initialization, improving error logging for connection failures. Update the user credit retrieval method to aggregate credits from all servers the user is a member of, enhancing accuracy. Introduce a cleanup command for removing old leaderboard entries, with appropriate error handling and user feedback for API interactions.
This commit is contained in:
Valerie 2025-05-26 05:35:50 -04:00
parent f1c5eef019
commit cbc2fb5ba9

View file

@ -100,21 +100,35 @@ class Leaderboard(commands.Cog):
self.admin_secret = await self.bot.get_shared_api_tokens("ruby_api")
if self.admin_secret.get("admin_secret"):
self.session = aiohttp.ClientSession()
# Test API connection
async with self.session.get(
f"{self.api_base_url}/leaderboard",
headers={"Authorization": self.admin_secret["admin_secret"]}
) as resp:
if resp.status != 200:
log.error(f"Failed to connect to API: Status {resp.status}")
except Exception as e:
log.error(f"Failed to initialize API connection: {e}")
# Don't return anything - initialization is optional
async def cog_load(self):
"""Initialize the cog when it's loaded."""
await self.initialize()
async def get_user_credits(self, user: discord.Member) -> int:
"""Get a user's total credits from Red's bank system."""
try:
return await bank.get_balance(user)
except Exception as e:
log.error(f"Error getting bank balance for {user}: {e}")
return 0
"""Get a user's total credits from all servers."""
total_credits = 0
# Get credits from all servers the user is in
for guild in self.bot.guilds:
if user in guild.members: # Only check servers where the user is a member
try:
credits = await bank.get_balance(user)
total_credits += credits
except Exception as e:
log.error(f"Error getting bank balance for {user} in {guild}: {e}")
continue
return total_credits
async def get_all_balances(self) -> List[dict]:
"""Get all users' credit balances across all servers."""
@ -164,23 +178,61 @@ class Leaderboard(commands.Cog):
return False
try:
if credits < 0:
credits = 0 # API doesn't accept negative values
async with self.session.post(
f"{self.api_base_url}/leaderboard",
headers={
"Authorization": self.admin_secret.get("admin_secret"),
"Authorization": self.admin_secret["admin_secret"],
"Content-Type": "application/json"
},
json={
"userId": user_id,
"username": username,
"userId": str(user_id),
"username": str(username),
"points": credits
}
) as resp:
return resp.status == 200
if resp.status == 200:
data = await resp.json()
if data.get("success"):
log.info(f"Updated leaderboard for {username}: {credits} credits")
return True
else:
log.error(f"API update failed: {data.get('error', 'Unknown error')}")
elif resp.status == 401:
log.error("Unauthorized: Invalid admin secret")
else:
log.error(f"API update failed: Status {resp.status}")
return False
except Exception as e:
log.error(f"API update failed: {e}")
return False
async def _get_api_leaderboard(self) -> Optional[list]:
"""Fetch the leaderboard from the API."""
if not self.session or not self.admin_secret or not self.admin_secret.get("admin_secret"):
return None
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:
return data["leaderboard"]
log.error("Invalid API response format")
elif resp.status == 401:
log.error("Unauthorized: Invalid admin secret")
else:
log.error(f"Failed to fetch leaderboard: Status {resp.status}")
return None
except Exception as e:
log.error(f"Error fetching leaderboard: {e}")
return None
@commands.group(name="globalboard", aliases=["glb"])
async def globalboard(self, ctx: commands.Context):
"""Global leaderboard commands."""
@ -332,7 +384,37 @@ class Leaderboard(commands.Cog):
if member.bot:
return
await self._try_api_update(str(member.id), str(member), after)
total_credits = await self.get_user_credits(member)
await self._try_api_update(str(member.id), str(member), total_credits)
@globalboard.command(name="cleanup")
@commands.is_owner()
async def cleanup_leaderboard(self, ctx: commands.Context):
"""Clean up old leaderboard entries (older than 30 days)."""
if not self.session or not self.admin_secret or not self.admin_secret.get("admin_secret"):
await ctx.send("API is not configured.")
return
try:
async with self.session.delete(
f"{self.api_base_url}/leaderboard",
headers={"Authorization": self.admin_secret["admin_secret"]}
) as resp:
if resp.status == 200:
data = await resp.json()
if data.get("success"):
await ctx.send(
f"Cleaned up {data['removedCount']} old entries. "
f"{data['remainingCount']} entries remaining."
)
else:
await ctx.send("Failed to clean up leaderboard.")
elif resp.status == 401:
await ctx.send("Unauthorized: Invalid admin secret")
else:
await ctx.send(f"Failed to clean up leaderboard: Status {resp.status}")
except Exception as e:
await ctx.send(f"Error cleaning up leaderboard: {e}")
def cog_unload(self):
"""Clean up when cog is unloaded."""