Add opt-in/opt-out functionality for global leaderboard in Leaderboard cog
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run

Implement user options to opt-out of the global leaderboard, ensuring their credits are not displayed. Update leaderboard display logic to only show users with 10,000 or more credits, enhancing user privacy and experience. Adjust error messages and embed descriptions accordingly for clarity.
This commit is contained in:
Valerie 2025-05-26 05:07:24 -04:00
parent 18d38ac395
commit 49902e8719

View file

@ -87,7 +87,12 @@ class Leaderboard(commands.Cog):
"cooldown": 60,
}
default_user = {
"opted_out": False
}
self.config.register_guild(**default_guild)
self.config.register_user(**default_user)
async def initialize(self):
"""Initialize optional API connection."""
@ -106,8 +111,7 @@ class Leaderboard(commands.Cog):
async def get_user_credits(self, user: discord.Member) -> int:
"""Get a user's total credits from Red's bank system."""
try:
# For per-server banks, get the balance from the user's current guild
return await bank.get_balance(user, guild=user.guild)
return await bank.get_balance(user)
except Exception as e:
log.error(f"Error getting bank balance for {user}: {e}")
return 0
@ -115,16 +119,21 @@ class Leaderboard(commands.Cog):
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
# Collect all unique members and sum their balances across all guilds
for guild in self.bot.guilds:
for member in guild.members:
if member.bot:
continue
# Skip opted-out users
if await self.config.user(member).opted_out():
continue
try:
# Get balance for this guild
credits = await bank.get_balance(member, guild=guild)
credits = await bank.get_balance(member)
if member.id not in all_users:
all_users[member.id] = {
@ -140,9 +149,9 @@ class Leaderboard(commands.Cog):
log.error(f"Error getting balance for {member} in {guild}: {e}")
continue
# Filter out users with no credits and sort by total
# Filter out users with less than minimum credits and sort by total
sorted_users = sorted(
[user for user in all_users.values() if user["points"] > 0],
[user for user in all_users.values() if user["points"] >= min_credits],
key=lambda x: x["points"],
reverse=True
)
@ -185,19 +194,20 @@ class Leaderboard(commands.Cog):
leaderboard_data = await self.get_all_balances()
if not leaderboard_data:
return await ctx.send("The leaderboard is currently empty!")
return await ctx.send("No users have 10,000 or more credits!")
items_per_page = 10
chunks = [leaderboard_data[i:i + items_per_page]
for i in range(0, len(leaderboard_data), items_per_page)]
if not chunks:
return await ctx.send("The leaderboard is currently empty!")
return await ctx.send("No users have 10,000 or more credits!")
embeds = []
for page_num, entries in enumerate(chunks, 1):
embed = discord.Embed(
title="🏆 Global Credits Leaderboard",
description="*Only showing users with 10,000+ credits*",
color=await ctx.embed_color()
)
@ -213,17 +223,52 @@ class Leaderboard(commands.Cog):
f"`{i}.` <@{user_id}> • **{humanize_number(credits)}** credits"
)
embed.description = "\n".join(description)
embed.description = embed.description + "\n\n" + "\n".join(description)
embed.set_footer(text=f"Page {page_num}/{len(chunks)} • Total Users: {len(leaderboard_data)}")
embeds.append(embed)
view = LeaderboardView(self, ctx, embeds)
view.message = await ctx.send(embed=embeds[0], view=view)
@globalboard.command(name="optout")
async def opt_out(self, ctx: commands.Context):
"""Opt out of the global leaderboard. Your credits will no longer be visible."""
user_settings = self.config.user(ctx.author)
current_status = await user_settings.opted_out()
if current_status:
await ctx.send("You are already opted out of the global leaderboard.")
return
await user_settings.opted_out.set(True)
await ctx.send("You have been opted out of the global leaderboard. Your credits will no longer be visible.")
@globalboard.command(name="optin")
async def opt_in(self, ctx: commands.Context):
"""Opt back into the global leaderboard."""
user_settings = self.config.user(ctx.author)
current_status = await user_settings.opted_out()
if not current_status:
await ctx.send("You are already opted into the global leaderboard.")
return
await user_settings.opted_out.set(False)
await ctx.send("You have been opted back into the global leaderboard. Your credits will now be visible.")
@globalboard.command(name="credits")
async def check_credits(self, ctx: commands.Context, member: commands.MemberConverter = None):
"""Check your credits or another member's credits."""
member = member or ctx.author
# Check if the target user has opted out
if await self.config.user(member).opted_out():
if member == ctx.author:
await ctx.send("You have opted out of the global leaderboard. Use `[p]globalboard optin` to show your credits again.")
else:
await ctx.send(f"{member.display_name} has opted out of the global leaderboard.")
return
credits = await self.get_user_credits(member)
# Get user's rank
@ -239,7 +284,7 @@ class Leaderboard(commands.Cog):
color=await ctx.embed_color()
)
if credits > 0:
if credits >= 10000:
embed.description = (
f"**User:** <@{member.id}>\n"
f"**Credits:** {humanize_number(credits)}\n"
@ -247,7 +292,7 @@ class Leaderboard(commands.Cog):
f"**ID:** {member.id}"
)
else:
embed.description = f"<@{member.id}> has no credits yet!"
embed.description = f"<@{member.id}> has less than 10,000 credits."
embed.set_thumbnail(url=member.display_avatar.url)
await ctx.send(embed=embed)