Skip to content

Commit d0cc451

Browse files
committed
feat: add /stats command showing karma given, received, and top users
1 parent 34e88c7 commit d0cc451

2 files changed

Lines changed: 101 additions & 0 deletions

File tree

src/backend/tables/db_karma_transaction.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,59 @@ async def oldest_transaction_to_user_since(
7979
return result.one()
8080

8181

82+
async def total_given_by(self, user_id: int) -> int:
83+
"""Total karma given out by a user (all time)."""
84+
async with self._session() as s:
85+
result = await s.exec(
86+
select(func.coalesce(func.sum(KarmaTransaction.amount), 0)).where(
87+
KarmaTransaction.performed_by == user_id,
88+
)
89+
)
90+
return result.one()
91+
92+
async def total_received_by(self, user_id: int) -> int:
93+
"""Total karma received by a user (all time)."""
94+
async with self._session() as s:
95+
result = await s.exec(
96+
select(func.coalesce(func.sum(KarmaTransaction.amount), 0)).where(
97+
KarmaTransaction.recipient_id == user_id,
98+
)
99+
)
100+
return result.one()
101+
102+
async def top_given_to(
103+
self, user_id: int, limit: int = 5
104+
) -> list[tuple[int, int]]:
105+
"""Top recipients of karma from this user. Returns [(recipient_id, total), ...]."""
106+
async with self._session() as s:
107+
result = await s.exec(
108+
select(
109+
KarmaTransaction.recipient_id,
110+
func.sum(KarmaTransaction.amount).label("total"),
111+
)
112+
.where(KarmaTransaction.performed_by == user_id)
113+
.group_by(KarmaTransaction.recipient_id)
114+
.order_by(func.sum(KarmaTransaction.amount).desc())
115+
.limit(limit)
116+
)
117+
return list(result.all())
118+
119+
async def top_received_from(
120+
self, user_id: int, limit: int = 5
121+
) -> list[tuple[int, int]]:
122+
"""Top givers of karma to this user. Returns [(performed_by, total), ...]."""
123+
async with self._session() as s:
124+
result = await s.exec(
125+
select(
126+
KarmaTransaction.performed_by,
127+
func.sum(KarmaTransaction.amount).label("total"),
128+
)
129+
.where(KarmaTransaction.recipient_id == user_id)
130+
.group_by(KarmaTransaction.performed_by)
131+
.order_by(func.sum(KarmaTransaction.amount).desc())
132+
.limit(limit)
133+
)
134+
return list(result.all())
135+
136+
82137
karma_transaction = KarmaTransactionDB()

src/cogs/commands/karma.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,52 @@ async def team_leaderboard(
175175
else:
176176
await interaction.followup.send(embed=embed)
177177

178+
@app_commands.command(name="stats", description="View your karma stats")
179+
@app_commands.describe(member="User to view stats for (defaults to yourself)")
180+
@has_karma_role()
181+
async def stats(
182+
self, interaction: discord.Interaction, member: discord.Member | None = None
183+
) -> None:
184+
await interaction.response.defer()
185+
target = member or interaction.user
186+
187+
total_given = await karma_transaction.total_given_by(target.id)
188+
total_received = await karma_transaction.total_received_by(target.id)
189+
top_given = await karma_transaction.top_given_to(target.id, limit=5)
190+
top_received = await karma_transaction.top_received_from(target.id, limit=5)
191+
192+
embed = discord.Embed(
193+
title=f"Karma Stats — {target.display_name}",
194+
color=discord.Color.gold(),
195+
)
196+
embed.set_thumbnail(url=target.display_avatar.url)
197+
198+
embed.add_field(name="Total Given", value=str(total_given), inline=True)
199+
embed.add_field(name="Total Received", value=str(total_received), inline=True)
200+
embed.add_field(name="\u200b", value="\u200b", inline=True) # spacer
201+
202+
if top_given:
203+
lines = []
204+
for recipient_id, total in top_given:
205+
m = interaction.guild.get_member(recipient_id)
206+
name = m.mention if m else f"Unknown ({recipient_id})"
207+
lines.append(f"{name} — **{total}**")
208+
embed.add_field(
209+
name="Most Given To", value="\n".join(lines), inline=True
210+
)
211+
212+
if top_received:
213+
lines = []
214+
for giver_id, total in top_received:
215+
m = interaction.guild.get_member(giver_id)
216+
name = m.mention if m else f"Unknown ({giver_id})"
217+
lines.append(f"{name} — **{total}**")
218+
embed.add_field(
219+
name="Most Received From", value="\n".join(lines), inline=True
220+
)
221+
222+
await interaction.followup.send(embed=embed)
223+
178224
async def _resolve_targets(
179225
self, message: discord.Message
180226
) -> list[tuple[discord.Member, int, bool]]:

0 commit comments

Comments
 (0)