Refactor leaderboard data fetching in Leaderboard cog to retrieve global leaderboard from API, enhancing error handling and caching. Update point management logic to calculate points dynamically and improve user interaction by updating points on member data changes.
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run
This commit is contained in:
parent
da273be3c3
commit
b688f7a605
1 changed files with 95 additions and 52 deletions
|
@ -133,41 +133,93 @@ class Leaderboard(commands.Cog):
|
|||
return total_points
|
||||
|
||||
async def _get_leaderboard(self) -> Optional[list]:
|
||||
"""Fetch and combine leaderboard data from bank and LevelUp."""
|
||||
"""Fetch the global leaderboard from the API."""
|
||||
if not self.admin_secret or not self.admin_secret.get("admin_secret"):
|
||||
log.error("Admin secret not configured")
|
||||
return None
|
||||
|
||||
if not self.session:
|
||||
log.error("Session not initialized")
|
||||
return None
|
||||
|
||||
try:
|
||||
all_users = {}
|
||||
|
||||
# Get all guild members
|
||||
for guild in self.bot.guilds:
|
||||
for member in guild.members:
|
||||
if member.bot:
|
||||
continue
|
||||
|
||||
points = await self.get_user_points(member)
|
||||
|
||||
if points > 0:
|
||||
all_users[str(member.id)] = {
|
||||
"userId": str(member.id),
|
||||
"username": str(member),
|
||||
"points": points
|
||||
}
|
||||
|
||||
# Sort by points and convert to list
|
||||
sorted_users = sorted(
|
||||
all_users.values(),
|
||||
key=lambda x: x["points"],
|
||||
reverse=True
|
||||
)
|
||||
|
||||
return sorted_users
|
||||
now = datetime.now(timezone.utc).timestamp()
|
||||
|
||||
# Return cached data if available and fresh
|
||||
if self._cache and now - self._last_update.get("leaderboard", 0) < self.cache_time:
|
||||
return self._cache.get("leaderboard")
|
||||
|
||||
async with self.session.get(
|
||||
f"{self.api_base_url}/leaderboard",
|
||||
headers={"Authorization": self.admin_secret.get("admin_secret")}
|
||||
) as resp:
|
||||
if resp.status == 200:
|
||||
data = await resp.json()
|
||||
if not isinstance(data, dict) or "leaderboard" not in data:
|
||||
log.error("Invalid API response format")
|
||||
return None
|
||||
self._cache["leaderboard"] = data["leaderboard"]
|
||||
self._last_update["leaderboard"] = now
|
||||
return self._cache["leaderboard"]
|
||||
elif resp.status == 401:
|
||||
log.error("Unauthorized: Invalid admin secret")
|
||||
return None
|
||||
else:
|
||||
log.error(f"Failed to fetch leaderboard: Status {resp.status}")
|
||||
return None
|
||||
except Exception as e:
|
||||
log.error(f"Error generating leaderboard: {e}")
|
||||
log.error(f"Error fetching leaderboard: {e}")
|
||||
return None
|
||||
|
||||
async def _update_points(self, user_id: str, username: str, points: int) -> bool:
|
||||
"""Update points is no longer needed as points are pulled from bank and LevelUp."""
|
||||
return True
|
||||
async def _update_points(self, user_id: str, username: str, points: int = None) -> bool:
|
||||
"""Update a user's points in the global leaderboard."""
|
||||
if not self.admin_secret or not self.admin_secret.get("admin_secret"):
|
||||
log.error("Admin secret not configured")
|
||||
return False
|
||||
|
||||
if not self.session:
|
||||
log.error("Session not initialized")
|
||||
return False
|
||||
|
||||
try:
|
||||
# If points not provided, calculate from Red's systems
|
||||
if points is None:
|
||||
member = None
|
||||
for guild in self.bot.guilds:
|
||||
member = guild.get_member(int(user_id))
|
||||
if member:
|
||||
break
|
||||
|
||||
if not member:
|
||||
return False
|
||||
|
||||
points = await self.get_user_points(member)
|
||||
|
||||
async with self.session.post(
|
||||
f"{self.api_base_url}/leaderboard",
|
||||
headers={
|
||||
"Authorization": self.admin_secret.get("admin_secret"),
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
json={
|
||||
"userId": user_id,
|
||||
"username": username,
|
||||
"points": points
|
||||
}
|
||||
) as resp:
|
||||
if resp.status == 200:
|
||||
# Clear cache to ensure fresh data on next fetch
|
||||
self._cache.pop("leaderboard", None)
|
||||
return True
|
||||
elif resp.status == 401:
|
||||
log.error("Unauthorized: Invalid admin secret")
|
||||
return False
|
||||
else:
|
||||
log.error(f"Failed to update points: Status {resp.status}")
|
||||
return False
|
||||
except Exception as e:
|
||||
log.error(f"Error updating points: {e}")
|
||||
return False
|
||||
|
||||
@commands.group(name="globalboard", aliases=["glb"])
|
||||
async def globalboard(self, ctx: commands.Context):
|
||||
|
@ -271,14 +323,22 @@ class Leaderboard(commands.Cog):
|
|||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
"""Award points for activity."""
|
||||
async def on_member_update(self, before: discord.Member, after: discord.Member):
|
||||
"""Update points when member's data changes."""
|
||||
if before.bot:
|
||||
return
|
||||
|
||||
# Update points in API when bank balance or XP changes
|
||||
await self._update_points(str(after.id), str(after))
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message: discord.Message):
|
||||
"""Update points periodically during user activity."""
|
||||
if message.author.bot or not message.guild:
|
||||
return
|
||||
|
||||
# Get guild settings
|
||||
guild_settings = await self.config.guild(message.guild).all()
|
||||
points_per_message = guild_settings["points_per_message"]
|
||||
min_length = guild_settings["min_message_length"]
|
||||
cooldown = guild_settings["cooldown"]
|
||||
|
||||
|
@ -295,22 +355,5 @@ class Leaderboard(commands.Cog):
|
|||
|
||||
self._last_update[f"msg_{message.author.id}"] = now
|
||||
|
||||
# Get current points
|
||||
leaderboard_data = await self._get_leaderboard()
|
||||
current_points = 0
|
||||
|
||||
if leaderboard_data:
|
||||
user_data = next(
|
||||
(entry for entry in leaderboard_data if entry.get("userId") == str(message.author.id)),
|
||||
None
|
||||
)
|
||||
if user_data:
|
||||
current_points = user_data.get("points", 0)
|
||||
|
||||
# Update points
|
||||
new_points = current_points + points_per_message
|
||||
await self._update_points(
|
||||
str(message.author.id),
|
||||
str(message.author),
|
||||
new_points
|
||||
)
|
||||
# Update points in API
|
||||
await self._update_points(str(message.author.id), str(message.author))
|
Loading…
Add table
Reference in a new issue