Skip to content

feat(events): auto-sync AOTW Discord winner roles - #5205

Open
wescopeland wants to merge 5 commits into
RetroAchievements:masterfrom
wescopeland:aotw-discord-roles
Open

feat(events): auto-sync AOTW Discord winner roles#5205
wescopeland wants to merge 5 commits into
RetroAchievements:masterfrom
wescopeland:aotw-discord-roles

Conversation

@wescopeland

@wescopeland wescopeland commented Sep 8, 2026

Copy link
Copy Markdown
Member

This PR allows the web server to sync the AOTW Winner role by reusing Discord API mechanisms we already have working for managing roles for muted users and handling display name changes.

A migration is included in this PR, which creates a event_winner_discord_role_grants table. This table is agnostic to the particular event in question, so it could in theory be reused for different events one day.

The new table has an expires_at timestamp field. When that date is surpassed, the role is wiped from all associated users. We cannot make a call to Discord's API that naively says "wipe Role X from all users in our server". This is part of the server intents that Discord no longer allows us to have. Instead, we need to use a lookup table and keep things in sync.

When this change goes live, we need to manually remove the AOTW Winner role from everyone on the server so the lookup table can be properly synchronized. We also need to strongly encourage people not to manually assign the role, because it won't be auto-removed when appropriate (as it wont exist in our lookup table).

I've updated the server environments so they have the role ID ready to go.

@wescopeland
wescopeland requested a review from a team September 8, 2026 22:56
@greptile-apps

greptile-apps Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge.

Summary

  • Tracks role grants and expiration.
  • Schedules synchronization every 15 minutes.
  • Reuses shared Discord member and role actions.
  • Fixes stale unlock and premature revocation handling.

Comment thread app/Community/Actions/SyncAotwWinnerDiscordRolesAction.php
Comment thread app/Community/Actions/SyncAotwWinnerDiscordRolesAction.php Outdated
Comment thread app/Community/Actions/SyncAotwWinnerDiscordRolesAction.php Outdated
$grant->update(['expires_at' => $current->active_until]);

continue;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is this trying to do? I assumed it was trying to extend the grant if the user earned the new AotW within the first few minutes of the last one expiring, but the expires_at->isFuture() would be false for that case.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The $grant->update() is there to handle the off-chance that an end date for an AOTW event achievement changes. This may be overly-defensive.

The continue within the conditional is there so we don't constantly remove and re-add roles a user should have during each sync attempt.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I got the general idea that it's an update and ignore. I just wasn't sure why.

I think the only time the AotW has ever been extended was due to a server outage, but I don't see any reason to remove the code since you've already written it.

$roleId,
shouldHaveRole: false,
reason: "AOTW winner removed: {$grant->user->display_name}",
);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If the user does earn the new AotW within a few minutes of the old one expiring, the role will be revoked here, then immediately restored when the $winners loop is processed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That's true. I wasn't sure if that was worth fixing - it seems unlikely to happen often and I wasn't sure if it was worth the complexity trade-off to address.

@Jamiras Jamiras Sep 9, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The AotW is supposed to take about 2 hours to earn, but there seems to be people who always start playing before the achievement is announced, so they get the AotW shortly after it is announced. This week it only took about 20 minutes:
image

I agree that it's probably not worth the effort if that's not what the other block was trying to address. Besides, sending the notification would further complicate any attempts to be smart about recycling the row.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, I've seen it happen usually at least once a week and they to ping someone to re-add it, but this is because the bot adds it before it gets around to removing it.

Another concern was people joining the server after getting the achievement, and thus don't get the role since they missed the assign window, that's a separate issue to this, of course, but unsure if that was also addressed.

Comment thread app/Community/Actions/SyncAotwWinnerDiscordRolesAction.php
Comment thread app/Community/AppServiceProvider.php
Comment thread app/Community/Listeners/SyncAotwWinnerDiscordRole.php
Comment thread app/Community/Listeners/SyncAotwWinnerDiscordRole.php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants