Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automate (former) champion badges #11

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,74 @@ async def clear_scores() -> None:

print(f"Deleted all clearable scores in {time.time() - start_time:.2f} seconds")

CHAMPION_BADGE_ID = 67
FORMER_CHAMPION_BADGE_ID = 66

async def update_champion_badges() -> None:
for rx in (0, 1, 2):
if rx == 0:
redis_board = "leaderboard"
modes = ("std", "taiko", "ctb", "mania")
elif rx == 1:
redis_board = "relaxboard"
modes = ("std", "taiko", "ctb")
else: # rx == 2:
redis_board = "autoboard"
modes = ("std",)

for mode in modes:
mode_int = mode + (4 * rx)
rank_key = f"ripple:{redis_board}:{mode}"

# this is updated in a cron so we need to also check current rank one
users_who_peaked_at_rank_one = list(
cmyui marked this conversation as resolved.
Show resolved Hide resolved
await db.fetchall(
"SELECT DISTINCT user_id FROM user_profile_history WHERE mode = %s AND `rank` = 1",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you check how many users are going to receive a badge that don't currently have it, from the switch from manual -> auto based on user_profile_history data?

Copy link
Member

@cmyui cmyui Dec 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a bit to consider here re. cases where someone cheated their way to #1 then got banned/unbanned -- I think this system would grant them the "former champion" badge in that case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a bit to consider here re. cases where someone cheated their way to #1 then got banned/unbanned

if we're not wiping this table when wiping a user for an unban then that's an issue in it's own way - that would mean their peak rank on their profile would already appear as whatever they peaked while cheating 😳

[mode_int]
)
)

current_rank_one_user_id = await redis.zrevrange(rank_key, 0, 0)
users_who_peaked_at_rank_one.append({"user_id": current_rank_one_user_id})
Copy link
Member

@cmyui cmyui Dec 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this fetched separately to guard against the case where the #1 is not yet inserted into user_profile_history? (iirc the job runs nightly?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, the API endpoint that the website uses to fetch peak rank does similar functionality (fetches peak from database and also current, takes whichever is lower)


for user in users_who_peaked_at_rank_one:
redis_rank = await redis.zrevrank(rank_key, user["user_id"])
current_rank = redis_rank + 1 if redis_rank is not None else None

if current_rank == 1:
await db.execute(
"DELETE FROM user_badges WHERE user = %s AND badge = %s",
[user["user_id"], FORMER_CHAMPION_BADGE_ID],
)

# user_badges has no unique key on (user, badge) so we have to check manually :(
existing_champion_badge = await db.fetch(
"SELECT 1 FROM user_badges WHERE user = %s AND badge = %s",
[user["user_id"], CHAMPION_BADGE_ID],
)

if not existing_champion_badge:
await db.execute(
"INSERT INTO user_badges (user, badge) (%s, %s)"
[user["user_id"], CHAMPION_BADGE_ID]
)
else:
await db.execute(
"DELETE FROM user_badges WHERE user = %s AND badge = %s",
[user["user_id"], CHAMPION_BADGE_ID],
)

# user_badges has no unique key on (user, badge) so we have to check manually :(
existing_former_champion_badge = await db.fetch(
"SELECT 1 FROM user_badges WHERE user = %s AND badge = %s",
[user["user_id"], FORMER_CHAMPION_BADGE_ID],
)

if not existing_former_champion_badge:
await db.execute(
"INSERT INTO user_badges (user, badge) (%s, %s)"
[user["user_id"], FORMER_CHAMPION_BADGE_ID]
)

async def main() -> None:
print("Starting Akatsuki cron")
Expand All @@ -335,6 +403,7 @@ async def main() -> None:
await fix_supporter_badges()
await update_total_submitted_score_counts()
await freeze_expired_freeze_timers()
await update_champion_badges()
# await clear_scores() # disabled as of 2022-07-19

await disconnect()
Expand Down