From 926dea676a57ec60cf40bf5d2aae476fc08e639c Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Sat, 30 Sep 2023 21:14:15 +0100 Subject: [PATCH 1/3] chore: bump to 5.8.0 --- Hammer/Hammer.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hammer/Hammer.csproj b/Hammer/Hammer.csproj index 6df3ffc..85b6d91 100644 --- a/Hammer/Hammer.csproj +++ b/Hammer/Hammer.csproj @@ -6,7 +6,7 @@ enable enable Linux - 5.7.0 + 5.8.0 From 52d9ccd78dc0b3094dfb4fb5d8f99dd0a9001d8c Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Sat, 30 Sep 2023 21:14:32 +0100 Subject: [PATCH 2/3] chore: rollForward latestMinor, don't allow prerelease --- global.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index 7cd6a1f..aaac9e0 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { "version": "7.0.0", - "rollForward": "latestMajor", - "allowPrerelease": true + "rollForward": "latestMinor", + "allowPrerelease": false } } \ No newline at end of file From 1db9e14e2c8e8ec50f8735acfc7c7804721fa379 Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Sat, 30 Sep 2023 21:14:44 +0100 Subject: [PATCH 3/3] feat: add /userinfo command --- CHANGELOG.md | 6 ++ Hammer/Commands/UserInfoCommand.cs | 117 +++++++++++++++++++++++++++++ Hammer/Services/BotService.cs | 1 + USAGE.md | 17 ++++- 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 Hammer/Commands/UserInfoCommand.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 97d009d..6183baf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [5.8.0] - 2023-09-30 + +### Added +- Added `/userinfo` command and "User Information" context menu. + ## [5.7.0] - 2023-09-06 ### Added @@ -438,6 +443,7 @@ No substantial changes. Commit 3b8259a6cfb82ec0f5f51804c1ac7f1f5880d014 fixed an - Hammer is released. +[5.8.0]: https://github.com/BrackeysBot/Hammer/releases/tag/v5.8.0 [5.7.0]: https://github.com/BrackeysBot/Hammer/releases/tag/v5.7.0 [5.6.1]: https://github.com/BrackeysBot/Hammer/releases/tag/v5.6.1 [5.6.0]: https://github.com/BrackeysBot/Hammer/releases/tag/v5.6.0 diff --git a/Hammer/Commands/UserInfoCommand.cs b/Hammer/Commands/UserInfoCommand.cs new file mode 100644 index 0000000..c08a11e --- /dev/null +++ b/Hammer/Commands/UserInfoCommand.cs @@ -0,0 +1,117 @@ +๏ปฟusing DSharpPlus; +using DSharpPlus.Entities; +using DSharpPlus.SlashCommands; +using DSharpPlus.SlashCommands.Attributes; +using Hammer.Configuration; +using Hammer.Extensions; +using Hammer.Services; +using X10D.DSharpPlus; + +namespace Hammer.Commands; + +/// +/// Represents a class which implements the userinfo command. +/// +internal sealed class UserInfoCommand : ApplicationCommandModule +{ + private readonly ConfigurationService _configurationService; + private readonly AltAccountService _altAccountService; + private readonly InfractionService _infractionService; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration service. + /// The alt account service. + /// The infraction service. + public UserInfoCommand(ConfigurationService configurationService, AltAccountService altAccountService, + InfractionService infractionService) + { + _configurationService = configurationService; + _altAccountService = altAccountService; + _infractionService = infractionService; + } + + [SlashCommand("userinfo", "Displays information about a user.")] + [SlashRequireGuild] + public async Task UserInfoAsync(InteractionContext context, + [Option("user", "The user whose information to view.", true)] + DiscordUser user) + { + DiscordGuild guild = context.Guild; + GuildConfiguration? configuration = _configurationService.GetGuildConfiguration(guild); + if (configuration is null) + { + await context.CreateResponseAsync("This guild is not configured.", true).ConfigureAwait(false); + return; + } + + bool staffRequested = context.Member.IsStaffMember(configuration); + DiscordMember? member = await user.GetAsMemberOfAsync(guild); + DiscordEmbed embed = CreateUserInfoEmbed(user, member, staffRequested, guild); + + await context.CreateResponseAsync(embed).ConfigureAwait(false); + } + + [ContextMenu(ApplicationCommandType.UserContextMenu, "User Information")] + [SlashRequireGuild] + public async Task UserInfoAsync(ContextMenuContext context) + { + DiscordGuild guild = context.Guild; + GuildConfiguration? configuration = _configurationService.GetGuildConfiguration(guild); + if (configuration is null) + { + await context.CreateResponseAsync("This guild is not configured.", true).ConfigureAwait(false); + return; + } + + bool staffRequested = context.Member.IsStaffMember(configuration); + DiscordEmbed embed = CreateUserInfoEmbed(context.TargetUser, context.TargetMember, staffRequested, guild); + await context.CreateResponseAsync(embed, true).ConfigureAwait(false); + } + + private DiscordEmbed CreateUserInfoEmbed(DiscordUser user, DiscordMember? member, bool staffRequested, DiscordGuild guild) + { + var embed = new DiscordEmbedBuilder(); + GuildConfiguration? configuration = _configurationService.GetGuildConfiguration(guild); + + if (member is null && !staffRequested) + { + embed.WithColor(DiscordColor.Red); + embed.WithTitle("User not found"); + embed.WithDescription("The specified user is not a member of this guild."); + return embed; + } + + // ReSharper disable ConditionIsAlwaysTrueOrFalse + embed.WithAuthor(user.GetUsernameWithDiscriminator(), iconUrl: user.GetAvatarUrl(ImageFormat.Png)); + embed.WithColor(member?.Color ?? DiscordColor.Gray); + embed.WithTitle("User Information"); + embed.WithThumbnail(user.AvatarUrl); + + embed.AddField("Username", user.GetUsernameWithDiscriminator(), true); + embed.AddField("ID", user.Id, true); + embed.AddFieldIf(!string.IsNullOrWhiteSpace(member?.Nickname), "Nickname", () => member!.Nickname, true); + embed.AddField("Created", Formatter.Timestamp(user.CreationTimestamp), true); + + embed.AddFieldIf(member is not null, "Joined", () => Formatter.Timestamp(member!.JoinedAt), true); + embed.AddFieldIf(member is not null, "Permission Level", () => member!.GetPermissionLevel(configuration), true); + + if (staffRequested) + { + int infractionCount = _infractionService.GetInfractionCount(user, guild); + int altCount = _altAccountService.GetAltsFor(user.Id).Count; + + embed.AddFieldIf(infractionCount > 0, "Infractions", infractionCount, true); + embed.AddFieldIf(altCount > 0, "Alt Accounts", altCount, true); + } + + if (member is null) + { + embed.WithFooter("โš ๏ธ This user is not currently in the server."); + } + // ReSharper restore ConditionIsAlwaysTrueOrFalse + + return embed; + } +} diff --git a/Hammer/Services/BotService.cs b/Hammer/Services/BotService.cs index 8a02fe4..9ea8419 100644 --- a/Hammer/Services/BotService.cs +++ b/Hammer/Services/BotService.cs @@ -95,6 +95,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) slashCommands.RegisterCommands(); slashCommands.RegisterCommands(); slashCommands.RegisterCommands(); + slashCommands.RegisterCommands(); slashCommands.RegisterCommands(); slashCommands.RegisterCommands(); RegisterEvents(); diff --git a/USAGE.md b/USAGE.md index e70c259..bd1a1f6 100644 --- a/USAGE.md +++ b/USAGE.md @@ -36,6 +36,12 @@ The default reaction equivalent is the ๐Ÿ”‡๏ธemoji (`:mute:`). The config key i The default reaction equivalent is the ๐Ÿ•“ emoji (`:clock4:`). The config key is `GUILD_ID.reactions.historyReaction`.k4: ). When this reaction is used, the history is instead sent as a DM to the staff member. +### ๐Ÿ‘ค User > Apps > User Information + +**Public action.** Displays information about a user. This is identical to the `/userinfo` command, except that the response **is ephemeral**. + +There is no reaction equivalent for this action. + # Slash Commands Below is an outline of every slash command currently implemented in Hammer, along with their descriptions and parameters. @@ -69,7 +75,7 @@ Unblocks a user, so that their message reports are acknowledged. |:----------|:---------|:-------------------|:-----------------------------------| | user | โœ… Yes | User mention or ID | The user whose reports to unblock. | -## Alt account management +## User management ### `/alt add` @@ -97,6 +103,14 @@ Views a user's alt accounts. |:----------|:---------|:-------------------|:-----------------------------------| | user | โœ… Yes | User mention or ID | The user whose alts to view. | +### `/userinfo` + +**Public command.** Displays information about a user. + +| Parameter | Required | Type | Description | +|:----------|:---------|:-------------------|:-----------------------------------| +| user | โœ… Yes | User mention or ID | The user whose info to view. | + ## Issuing and revoking infractions ### `/ban` @@ -387,5 +401,6 @@ Below is a table outlining all the commands and whether or not they have ephemer | `/unmute` | โœ… Yes | | `/unban` | โœ… Yes | | `/unblockreports` | โœ… Yes | +| `/userinfo` | โŒ No | | `/viewmessage` | โŒ No | | `/warn` | โœ… Yes |