Repository navigation
Feature/context commands - #404
Conversation
…ntext command - /bday show now takes an optional user to show that member's birthday - remove the standalone /bday user slash command - add a View Birthday user context-menu command (ephemeral)
- extract shared duel logic into StartDuel so both entry points reuse it - context menu always starts a non-mute duel (no silent 5-minute timeout)
…mounts - add a Gift Tokens user context command that prompts for the amount via a modal - share gift validation between the slash command and the modal path - SECURITY: reject amount <= 0. TransferTokens reversed the transfer direction on a negative amount, so /casino tokens gift <user> -100 drained the target's tokens.
…ext command - /profile takes an optional user and defaults to the caller - View Profile is an ephemeral user context-menu command - card is removed after 3 minutes and the failure message after 10 seconds, matching the legacy !profile behaviour
🚀 Deploy this PRCode-only changes
Manifest changes (e.g. new services in
|
| catch (Exception e) | ||
| { | ||
| await LoggingService.LogAction($"Error while generating profile card for {user.Username}.\nEx:{e}", | ||
| ExtendedLogSeverity.LowWarning); | ||
| } |
There was a problem hiding this comment.
🟡 Changes recommended
There is at least one confirmed interaction-flow bug (deferred interaction can fail without a follow-up on exception) that can leave users with a stuck/failed command execution.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds Discord user context-menu commands and expands slash-command support so common user-focused actions (profile viewing, dueling, token gifting, birthday lookup) are accessible from Discord’s right-click UI, and updates docs to reflect the new entry points.
Changes:
- Add
/profileslash command + View Profile user context command via a newProfileSlashModule. - Add Duel and Gift Tokens user context commands, including a modal-driven token amount prompt.
- Extend
/bday showto support optional per-user lookup and add View Birthday user context command; update feature/codebase docs accordingly.
File summaries
| File | Description |
|---|---|
| docs/features.md | Documents the new context-menu entry points for profiles, casino gifting, duels, and birthdays. |
| docs/codebase.md | Adds ProfileSlashModule to the documented module layout and domain grouping. |
| DiscordBot/Modules/Profiles/ProfileSlashModule.cs | Implements /profile and View Profile user context command. |
| DiscordBot/Modules/Fun/DuelSlashModule.cs | Adds Duel user context command that starts a normal duel. |
| DiscordBot/Modules/Fun/Casino/CasinoSlashModule.cs | Adds Gift Tokens user context command using a modal for amount entry and shared validation. |
| DiscordBot/Modules/BirthdaySlashModule.cs | Updates /bday show to optionally target a user and adds View Birthday user context command. |
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| catch (Exception e) | ||
| { | ||
| await LoggingService.LogAction($"Error while generating profile card for {user.Username}.\nEx:{e}", | ||
| ExtendedLogSeverity.LowWarning); | ||
| } |
| public string Amount { get; set; } = string.Empty; | ||
| } | ||
|
|
||
| [ModalInteraction("casino_gift_tokens:*", true)] |
…mmands - Set Birthday: modal prompts for the date, then sets it (admin only) - Remove Birthday: confirm/cancel buttons guard the destructive right-click action - Remove Badge: multi-select menu of the member badges doubles as confirmation; a modal cannot list per-user badges because modal select options are declared at compile time Slash commands keep identical behaviour and now share helpers with the context commands so the two cannot drift.
…ext commands - View Casino History: opens the member token transaction history (admin only) - Set Tokens / Add Tokens: share one amount modal, with the action carried in the custom id - Amounts are digits only, so a negative value cannot invert the meaning of add or set - Casino channel restriction plus admin and opener checks enforced on every new path, including the modal submit Slash commands keep identical behaviour and now share helpers with the context commands.
Adds /coinflip, /roll and /slap and removes !coinflip, !roll, !d20 and !slap. Dice notation moves into Domain/Dice as a pure parser and now accepts flat additive modifiers, so /roll 2d6+4 and /roll 1d20+1d4-1 work. A lone bare number keeps its legacy meaning (20 is 1d20). Keep/drop, exploding, reroll and success-counting remain unsupported. Reply wording is extracted to FunRollFormatter so it can be unit tested, and /slap reads its FuzzTable at most once per process instead of awaiting a Discord log call on every invocation. !d20 is not ported; /roll 1d20 covers it.
Adds /ftoc, /ctof and /curr, and deletes ConvertModule along with !translate and !currencyname. /curr autocompletes currency codes, matching on code prefix or currency name, so both sek and krona find SEK. Discord requires required options to precede optional ones, so the required 'from' option comes first and amount/to follow with defaults of 1 and usd. CurrencyService gains GetCurrenciesAsync and a semaphore-guarded lazy build, since autocomplete and command handling can now populate the currency list concurrently. GetCurrencyName loses its only caller to the autocomplete accessor and is removed. Program now sets EnableAutocompleteHandlers explicitly. It already defaults to true, but /curr depends on it.
…mands Adds /members, /join-date [user], /karma, /top and /top-karma [interval], and deletes RankModule and ProfileModule along with !top, !topk, !topkw, !topkm, !topky, !karma and !join-date. /top-karma collapses four commands into one Choice option covering all time, week, month and year. Leaderboard row formatting moves to RankEmbedFormatter so the padding rules are covered by tests. The legacy embed builder blocked on async work inside a LINQ Select via .Result; the rewrite awaits the lookups directly. The leaderboard commands used to return without replying when the database query was unavailable, which would hang a slash interaction. That path now answers ephemerally.
| catch (Exception) | ||
| { | ||
| _slapObjectsLoaded = true; | ||
|
|
||
| await LoggingService.LogChannelAndFile($"Error while loading '{Settings.FunCommands.SlapObjectsTable}'.", | ||
| ExtendedLogSeverity.LowWarning); | ||
| return false; | ||
| } |
| catch (Exception e) | ||
| { | ||
| // Without this the interaction would never be answered and Discord would show a timeout. | ||
| await LoggingService.LogChannelAndFile($"Failed to generate a leaderboard embed.\n{e}", | ||
| ExtendedLogSeverity.LowWarning); | ||
| await Context.Interaction.RespondAsync("❌ Could not build the leaderboard right now.", ephemeral: true); | ||
| return; | ||
| } |
| if (target < 1) | ||
| message = " :game_die: " + message; | ||
| else | ||
| message = $"{(result.Total >= target ? " :white_check_mark: " : " :x: ")}{message} [Needed: {target}]"; |
| } | ||
| catch (Exception) | ||
| { | ||
| _slapObjectsLoaded = true; |
| { | ||
| SlapObjects.Unique = true; | ||
| SlapObjects.Load(Settings.FunCommands.SlapObjectsTable!); | ||
| _slapObjectsLoaded = true; |
|
✅ PR deployed to dev! Image: |
The Assign Badge user context command now offers the target's assignable badges in a multi-select menu, matching the Remove Badge command. Only badges the target does not already hold are listed, since offering one they own can only fail. The first 25 options are shown, with a notice pointing at /admin badge assign for the rest. The modal, BadgeIdentifierMaxLength and this module's ResolveBadgeByIdentifier are deleted; the latter only existed to resolve text typed into the modal. The /admin badge commands keep their own copy and are unaffected. Assign Badge now assigns any number of badges and reports a summary rather than a single-assignment embed. SanitizeSelectText moves from AdminSlashModule to StringExtensions as ToSelectOptionText so both select menu builders share one implementation.
|
✅ PR deployed to dev! Image: |
No description provided.