Skip to content

Commit

Permalink
fix(stars): various stars fixes (#447)
Browse files Browse the repository at this point in the history
* fix leaderboard

* Allow adding/removing multiple stars; fix /stars me
  • Loading branch information
sloria authored Feb 22, 2022
1 parent 1c93f25 commit 32fd2a9
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 25 deletions.
23 changes: 16 additions & 7 deletions bot/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,8 +730,8 @@ async def remove_scheduled_event(self, *, event_id: int):

##### Stars #####

async def give_star(
self, *, from_user_id: int, to_user_id: int, message_id: int | None
async def give_stars(
self, *, from_user_id: int, to_user_id: int, n_stars: int, message_id: int | None
):
created_at = now()
# Insert a star log
Expand All @@ -754,12 +754,14 @@ async def give_star(
)
stmt = stmt.on_conflict_do_update(
index_elements=(user_stars.c.user_id,),
set_=dict(star_count=user_stars.c.star_count + 1, updated_at=created_at),
set_=dict(
star_count=user_stars.c.star_count + n_stars, updated_at=created_at
),
)
await self.db.execute(stmt)

async def remove_star(
self, *, from_user_id: int, to_user_id: int, message_id: int | None
async def remove_stars(
self, *, from_user_id: int, to_user_id: int, n_stars: int, message_id: int | None
):
created_at = now()
# Insert a star log
Expand All @@ -782,7 +784,11 @@ async def remove_star(
)
stmt = stmt.on_conflict_do_update(
index_elements=(user_stars.c.user_id,),
set_=dict(star_count=user_stars.c.star_count - 1, updated_at=created_at),
set_=dict(
# TODO: don't allow negative count
star_count=user_stars.c.star_count - n_stars,
updated_at=created_at,
),
)
await self.db.execute(stmt)

Expand Down Expand Up @@ -819,7 +825,10 @@ async def set_user_stars(

async def list_user_stars(self, limit: int) -> list[Mapping]:
return await self.db.fetch_all(
user_stars.select().order_by(user_stars.c.star_count.desc()).limit(limit)
user_stars.select()
.where(user_stars.c.star_count > 0)
.order_by(user_stars.c.star_count.desc())
.limit(limit)
)


Expand Down
58 changes: 40 additions & 18 deletions bot/exts/stars.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async def make_user_star_count_embed(
user: disnake.Member | disnake.User, *, description: str | None = None
) -> Embed:
embed = Embed(
description=description,
description=description or Embed.Empty,
color=disnake.Color.yellow(),
)
user_stars = await store.get_user_stars(user.id)
Expand Down Expand Up @@ -52,43 +52,58 @@ async def stars_command(self, inter: GuildCommandInteraction):

@stars_command.sub_command(name="give")
@commands.has_permissions(kick_members=True) # Staff
async def stars_give(self, inter: GuildCommandInteraction, user: disnake.User):
async def stars_give(
self,
inter: GuildCommandInteraction,
user: disnake.User,
n: int = Param(ge=0, default=1),
):
"""(Authorized users only) Give a star to a user
Parameters
----------
user: The user to give a star to
n: The number of stars to give
"""
assert inter.user is not None
async with store.transaction():
await store.give_star(
from_user_id=inter.user.id, to_user_id=user.id, message_id=None
await store.give_stars(
from_user_id=inter.user.id, to_user_id=user.id, n_stars=n, message_id=None
)
noun = f"{STAR_EMOJI}s" if n > 1 else f"a {STAR_EMOJI}"
embed = await make_user_star_count_embed(
description=f"{user.mention} received a {STAR_EMOJI} from {inter.user.mention}",
description=f"{user.mention} received {noun} from {inter.user.mention}",
user=user,
)
await inter.send(embed=embed)

@stars_command.sub_command(name="remove")
@commands.has_permissions(kick_members=True) # Staff
async def stars_remove(self, inter: GuildCommandInteraction, user: disnake.User):
async def stars_remove(
self,
inter: GuildCommandInteraction,
user: disnake.User,
n: int = Param(ge=0, default=1),
):
"""(Authorized users only) Remove a star from a user
Parameters
----------
user: The user to remove a star from
n: The number of stars to remove
"""
assert inter.user is not None
async with store.transaction():
await store.remove_star(
await store.remove_stars(
from_user_id=inter.user.id,
to_user_id=user.id,
n_stars=n,
message_id=None,
)
assert inter.user is not None
noun = f"{STAR_EMOJI}s" if n > 1 else f"a {STAR_EMOJI}"
embed = await make_user_star_count_embed(
description=f"{user.mention} had a {STAR_EMOJI} removed by {inter.user.mention}",
description=f"{user.mention} had {noun} removed by {inter.user.mention}",
user=user,
)
await inter.send(embed=embed)
Expand Down Expand Up @@ -120,16 +135,21 @@ async def stars_set(
@stars_command.sub_command(name="board")
async def stars_board(self, inter: GuildCommandInteraction):
"""Show the star leaderboard"""
records = await store.list_user_stars(limit=10)
records = await store.list_user_stars(limit=100)
description = ""
# TODO: use a paginated embed
# https://discord.com/developers/docs/resources/channel#embed-limits
max_description_length = 4096
for i, record in enumerate(records):
member = await inter.guild.get_or_fetch_member(record["user_id"])
if not member:
continue
line = f"{i+1}. {member.display_name} | `{member.name}#{member.discriminator}` | {record['star_count']} {STAR_EMOJI}\n"
if len(description) + len(line) < max_description_length:
description += line
embed = Embed(
title=f"{STAR_EMOJI} Leaderboard",
description="\n".join(
[
f"{i+1}. <@{record['user_id']}> | {record['star_count']} {STAR_EMOJI}"
for i, record in enumerate(records)
if record["star_count"] > 0
]
),
description=description,
color=disnake.Color.yellow(),
)
await inter.response.send_message(embed=embed)
Expand All @@ -156,9 +176,10 @@ async def on_raw_reaction_add(self, payload: disnake.RawReactionActionEvent) ->
to_user = message.author

async with store.transaction():
await store.give_star(
await store.give_stars(
from_user_id=from_user.id,
to_user_id=to_user.id,
n_stars=1,
message_id=message.id,
)
channel = cast(
Expand All @@ -181,9 +202,10 @@ async def on_raw_reaction_remove(
to_user = message.author

async with store.transaction():
await store.remove_star(
await store.remove_stars(
from_user_id=from_user.id,
to_user_id=to_user.id,
n_stars=1,
message_id=message.id,
)
channel = cast(
Expand Down

0 comments on commit 32fd2a9

Please sign in to comment.