Semi-Automatic Top Helper Assignment by Zabuzard · Pull Request #1303 · Together-Java/TJ-Bot
Motivation
Currently we do the monthly Top Helpers manually with the aid of /top-helpers, showing a list like this:
Everything beyond that is manual, i.e.:
- Clearing the current top helpers from the role
- Assigning the new top helpers to the role
- writing an announcement in
#hall-of-fame
The problem with this is that, because its mostly manual work, we kept forgetting and skipping it for a few months already. Not good 😢
Solution
This PR introduces a semi-automatic routine that does the Top Helper assignment and announcement automatically with minimal and simple investman by a human.
The routine starts on the 1st of each month at 12:00 o'clock (or can be started manually using /top-helpers assign) and creates a dialog in a trusted channel (e.g. community-commands).
The dialog proposes a list of Top Helpers (as known from the existing /top-helpers command, now renamed to /top-helpers show).
A trusted user can now select from this list everyone who should become Top Helper. The routine then continues automatically clearing the Top Helper role and assigning the role to the selected people.
Additionally, the routine then continues to ask if it should make a generic announcement (in #hall-of-fame) as well or if that should be skipped.
Impressions
Flexibility
The routine can be cancelled at any point in case needed by pressing the Cancel button. It can also be started outside of the normal schedule by using /top-helpers assign.
Adding users to the list of Top Helpers that were not proposed by the bot or otherwise modifying the list is possible by simply clicking No on the question for the generic announcement. Like, roll with the automatic assignment of the routine, dont send an automatic announcement and then edit the Role manually as we used to before this PR already. Then, if desired, simply send an announcement with the modified list yourself.
The last step with the generic announcement was made optional on purpose since a huge appeal of the "announcements made by a human" always was to include a funny image. We still want this to be possible, so if someone is in the mood to create such an image they can click on No and skip the generic announcement, writing one themselves. In practice however, people will often not have the time for this, so the generic announcement is a good way out, definitely better than no announcement.
Config
This introduces a new block to the config:
"topHelpers": { "rolePattern": "Top Helper.*", "assignmentChannelPattern": "community-commands", "announcementChannelPattern": "hall-of-fame" }
Further, the patterns for the Top Helper role have been adjusted everywhere in the config from Top Helpers .+ to Top Helper.*. This allows for renaming the role from e.g. Top Helpers August to Top Helper, while still being compatible with the current role name.
(this is a user suggestion with lots of upvotes, so it will likely be put in action soon anyways)
Discord
So while at it, it is proposed (but not required) to rename the role Top Helpers August etc to Top Helper.
Commands
The existing slashcommand /top-helpers was changed into two subcommands:
/top-helpers show: shows the list of top helpers, i.e. what/top-helpersdid already/top-helpers assign: manual trigger for the routine added in this PR
Code
Most changes in this PR revolve around the addition of a new class called TopHelpersAssignmentRoutine, which deals with the entire dialog.
Some of the logic in this routine is shared with the existing slash command TopHelpersCommand, so a helper class was added to allow shared logic: TopHelpersService.
The service mostly deals with the actual computation of Top Helpers (using the DB), retrieval of user data (helper IDs to JDA Member) and visual presentation (ASCII table). This code is not new and merely moved from TopHelpersCommand over to TopHelpersService, sometimes with slight modifications to also fit the needs of TopHelpersAssignmentRoutine.
Schedule
The routine needs the ability to execute "once a month at a fixed time". We already had similar code to enable that present in ModAuditLogRoutine. This code has been elevated from there to Routine, to allow others to use the logic as well.
I.e. while the methods Schedule.atFixedRateFromNextFixedTime(...) and Schedule.atFixedHour(...) are new, their code is not new and was part of ModAuditLogRoutine already.
Slash Command (TopHelpersCommand)
The slash command stays mostly unchanged. Modifications include it now using sub-commands (see its constructor), simple routing code in onSlashCommand to determine which sub-command was triggered and in case of the new sub-command show it just forwards in assignTopHelpers to the routine assignmentRoutine.startDialogFor(...).
To enable that, it got the routine as dependency at construction.
Routine (TopHelpersAssignmentRoutine)
The code for this is mostly straightforward, albeit a bit annoying due to JDA not making it easy to create dialogs and constantly interrupting code-flow.
The method order goes from top to bottom to represent the flow of the routine, it should mostly read in a straightforward way without jumping around much.
Error Handling
Error handling is mostly similar but has slight differences. These mostly revolve around the fact whether there was already a message posted by the bot that can be edited or if a new message needs to be posted.
And if there was a message already, whether it includes buttons and similar that need to be cleared.
Remarks
A few things to highlight:
- progress during the routine is reported to the user by appending new lines to the existing message, e.g.
...editOriginal(message + "\n...") - each new step in the routine clears buttons and selection-menus of the previous step, e.g.
.setActionRow(...)or alsosetComponents() - the routine needs to use
componentIdInteractormanually as it is not a traditional slash or context command. I.e. it can not extend from something likeSlashCommandAdapterbringing component-ID logic out of the box and needs to instead implementUserInteractormanually. We did that already in the past withScamBlockerin the same way.



