Fix some issues with slash commands & add missing docs (#46)

mctaylors: "but I use Rider too..."
This commit is contained in:
Octol1ttle 2023-07-09 20:15:39 +05:00 committed by GitHub
parent abbb58f801
commit 2dd9f023ef
Signed by: GitHub
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 916 additions and 1398 deletions

View file

@ -19,31 +19,14 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DiffPlex" Version="1.7.1" /> <PackageReference Include="DiffPlex" Version="1.7.1"/>
<PackageReference Include="Humanizer.Core.ru" Version="2.14.1" /> <PackageReference Include="Humanizer.Core.ru" Version="2.14.1"/>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1"/>
<PackageReference Include="Remora.Discord" Version="2023.3.0" /> <PackageReference Include="Remora.Discord" Version="2023.3.0"/>
</ItemGroup>
<!-- TODO: remove this when done -->
<ItemGroup>
<Compile Remove="old\**" />
<Compile Update="Messages.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Messages.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="old\**" />
<EmbeddedResource Update="Messages.resx"> <EmbeddedResource Update="Messages.resx">
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Messages.Designer.cs</LastGenOutput> <LastGenOutput>Messages.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Remove="old\**" />
</ItemGroup>
</Project> </Project>

View file

@ -42,15 +42,15 @@ public class KickCommandGroup : CommandGroup {
} }
/// <summary> /// <summary>
/// A slash command that kicks a Discord user with the specified reason. /// A slash command that kicks a Discord member with the specified reason.
/// </summary> /// </summary>
/// <param name="target">The user to kick.</param> /// <param name="target">The member to kick.</param>
/// <param name="reason"> /// <param name="reason">
/// The reason for this kick. Must be encoded with <see cref="Extensions.EncodeHeader" /> when passed to /// The reason for this kick. Must be encoded with <see cref="Extensions.EncodeHeader" /> when passed to
/// <see cref="IDiscordRestGuildAPI.RemoveGuildMemberAsync" />. /// <see cref="IDiscordRestGuildAPI.RemoveGuildMemberAsync" />.
/// </param> /// </param>
/// <returns> /// <returns>
/// A feedback sending result which may or may not have succeeded. A successful result does not mean that the user /// A feedback sending result which may or may not have succeeded. A successful result does not mean that the member
/// was kicked and vice-versa. /// was kicked and vice-versa.
/// </returns> /// </returns>
[Command("kick", "кик")] [Command("kick", "кик")]

View file

@ -44,16 +44,16 @@ public class MuteCommandGroup : CommandGroup {
} }
/// <summary> /// <summary>
/// A slash command that mutes a Discord user with the specified reason. /// A slash command that mutes a Discord member with the specified reason.
/// </summary> /// </summary>
/// <param name="target">The user to mute.</param> /// <param name="target">The member to mute.</param>
/// <param name="duration">The duration for this mute. The user will be automatically unmuted after this duration.</param> /// <param name="duration">The duration for this mute. The member will be automatically unmuted after this duration.</param>
/// <param name="reason"> /// <param name="reason">
/// The reason for this mute. Must be encoded with <see cref="Extensions.EncodeHeader" /> when passed to /// The reason for this mute. Must be encoded with <see cref="Extensions.EncodeHeader" /> when passed to
/// <see cref="IDiscordRestGuildAPI.ModifyGuildMemberAsync" />. /// <see cref="IDiscordRestGuildAPI.ModifyGuildMemberAsync" />.
/// </param> /// </param>
/// <returns> /// <returns>
/// A feedback sending result which may or may not have succeeded. A successful result does not mean that the user /// A feedback sending result which may or may not have succeeded. A successful result does not mean that the member
/// was muted and vice-versa. /// was muted and vice-versa.
/// </returns> /// </returns>
/// <seealso cref="UnmuteUserAsync" /> /// <seealso cref="UnmuteUserAsync" />
@ -65,8 +65,7 @@ public class MuteCommandGroup : CommandGroup {
public async Task<Result> MuteUserAsync( public async Task<Result> MuteUserAsync(
[Description("Member to mute")] IUser target, [Description("Member to mute")] IUser target,
[Description("Mute reason")] string reason, [Description("Mute reason")] string reason,
[Description("Mute duration")] [Description("Mute duration")] TimeSpan duration) {
TimeSpan duration) {
if (!_context.TryGetContextIDs(out var guildId, out var channelId, out var userId)) if (!_context.TryGetContextIDs(out var guildId, out var channelId, out var userId))
return Result.FromError( return Result.FromError(
new ArgumentNullError(nameof(_context), "Unable to retrieve necessary IDs from command context")); new ArgumentNullError(nameof(_context), "Unable to retrieve necessary IDs from command context"));
@ -156,15 +155,15 @@ public class MuteCommandGroup : CommandGroup {
} }
/// <summary> /// <summary>
/// A slash command that unmutes a Discord user with the specified reason. /// A slash command that unmutes a Discord member with the specified reason.
/// </summary> /// </summary>
/// <param name="target">The user to unmute.</param> /// <param name="target">The member to unmute.</param>
/// <param name="reason"> /// <param name="reason">
/// The reason for this unmute. Must be encoded with <see cref="Extensions.EncodeHeader" /> when passed to /// The reason for this unmute. Must be encoded with <see cref="Extensions.EncodeHeader" /> when passed to
/// <see cref="IDiscordRestGuildAPI.ModifyGuildMemberAsync" />. /// <see cref="IDiscordRestGuildAPI.ModifyGuildMemberAsync" />.
/// </param> /// </param>
/// <returns> /// <returns>
/// A feedback sending result which may or may not have succeeded. A successful result does not mean that the user /// A feedback sending result which may or may not have succeeded. A successful result does not mean that the member
/// was unmuted and vice-versa. /// was unmuted and vice-versa.
/// </returns> /// </returns>
/// <seealso cref="MuteUserAsync" /> /// <seealso cref="MuteUserAsync" />
@ -175,10 +174,8 @@ public class MuteCommandGroup : CommandGroup {
[RequireBotDiscordPermissions(DiscordPermission.ModerateMembers)] [RequireBotDiscordPermissions(DiscordPermission.ModerateMembers)]
[Description("Unmute member")] [Description("Unmute member")]
public async Task<Result> UnmuteUserAsync( public async Task<Result> UnmuteUserAsync(
[Description("Member to unmute")] [Description("Member to unmute")] IUser target,
IUser target, [Description("Unmute reason")] string reason) {
[Description("Unmute reason")]
string reason) {
if (!_context.TryGetContextIDs(out var guildId, out var channelId, out var userId)) if (!_context.TryGetContextIDs(out var guildId, out var channelId, out var userId))
return Result.FromError( return Result.FromError(
new ArgumentNullError(nameof(_context), "Unable to retrieve necessary IDs from command context")); new ArgumentNullError(nameof(_context), "Unable to retrieve necessary IDs from command context"));

View file

@ -33,9 +33,18 @@ public class RemindCommandGroup : CommandGroup {
_userApi = userApi; _userApi = userApi;
} }
/// <summary>
/// A slash command that schedules a reminder with the specified text.
/// </summary>
/// <param name="in">The period of time which must pass before the reminder will be sent.</param>
/// <param name="message">The text of the reminder.</param>
/// <returns>A feedback sending result which may or may not have succeeded.</returns>
[Command("remind")] [Command("remind")]
[Description("Create a reminder")] [Description("Create a reminder")]
public async Task<Result> AddReminderAsync(TimeSpan duration, string text) { public async Task<Result> AddReminderAsync(
[Description("After what period of time mention the reminder")]
TimeSpan @in,
[Description("Reminder message")] string message) {
if (!_context.TryGetContextIDs(out var guildId, out var channelId, out var userId)) if (!_context.TryGetContextIDs(out var guildId, out var channelId, out var userId))
return Result.FromError( return Result.FromError(
new ArgumentNullError(nameof(_context), "Unable to retrieve necessary IDs from command context")); new ArgumentNullError(nameof(_context), "Unable to retrieve necessary IDs from command context"));
@ -44,13 +53,13 @@ public class RemindCommandGroup : CommandGroup {
if (!userResult.IsDefined(out var user)) if (!userResult.IsDefined(out var user))
return Result.FromError(userResult); return Result.FromError(userResult);
var remindAt = DateTimeOffset.UtcNow.Add(duration); var remindAt = DateTimeOffset.UtcNow.Add(@in);
(await _dataService.GetMemberData(guildId.Value, userId.Value, CancellationToken)).Reminders.Add( (await _dataService.GetMemberData(guildId.Value, userId.Value, CancellationToken)).Reminders.Add(
new Reminder { new Reminder {
RemindAt = remindAt, RemindAt = remindAt,
Channel = channelId.Value, Channel = channelId.Value,
Text = text Text = message
}); });
var embed = new EmbedBuilder().WithSmallTitle(string.Format(Messages.ReminderCreated, user.GetTag()), user) var embed = new EmbedBuilder().WithSmallTitle(string.Format(Messages.ReminderCreated, user.GetTag()), user)

View file

@ -5,11 +5,8 @@ using Boyfriend.Data;
using Boyfriend.Services; using Boyfriend.Services;
using Remora.Commands.Attributes; using Remora.Commands.Attributes;
using Remora.Commands.Groups; using Remora.Commands.Groups;
using Remora.Discord.API.Abstractions.Objects;
using Remora.Discord.API.Abstractions.Rest; using Remora.Discord.API.Abstractions.Rest;
using Remora.Discord.Commands.Attributes;
using Remora.Discord.Commands.Contexts; using Remora.Discord.Commands.Contexts;
using Remora.Discord.Commands.Feedback.Messages;
using Remora.Discord.Commands.Feedback.Services; using Remora.Discord.Commands.Feedback.Services;
using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Embeds;
using Remora.Discord.Extensions.Formatting; using Remora.Discord.Extensions.Formatting;
@ -44,10 +41,9 @@ public class SettingsCommandGroup : CommandGroup {
/// <returns> /// <returns>
/// A feedback sending result which may or may not have succeeded. /// A feedback sending result which may or may not have succeeded.
/// </returns> /// </returns>
[Command("settings list")] [Command("settingslist")]
[Description("Shows settings list for this server")] [Description("Shows settings list for this server")]
[SuppressInteractionResponse(suppress: true)] public async Task<Result> ListSettingsAsync() {
public async Task<Result> SendSettingsListAsync() {
if (!_context.TryGetContextIDs(out var guildId, out _, out _)) if (!_context.TryGetContextIDs(out var guildId, out _, out _))
return Result.FromError( return Result.FromError(
new ArgumentNullError(nameof(_context), "Unable to retrieve necessary IDs from command context")); new ArgumentNullError(nameof(_context), "Unable to retrieve necessary IDs from command context"));
@ -77,21 +73,21 @@ public class SettingsCommandGroup : CommandGroup {
.Build(); .Build();
if (!embed.IsDefined(out var built)) return Result.FromError(embed); if (!embed.IsDefined(out var built)) return Result.FromError(embed);
return (Result)await _feedbackService.SendContextualEmbedAsync( return (Result)await _feedbackService.SendContextualEmbedAsync(built, ct: CancellationToken);
built, ct: CancellationToken, options: new FeedbackMessageOptions(MessageFlags: MessageFlags.Ephemeral));
} }
/// <summary> /// <summary>
/// A slash command that modifies per-guild settings. /// A slash command that modifies per-guild settings.
/// </summary> /// </summary>
/// <returns> /// <param name="setting">The setting to modify.</param>
/// A feedback sending result which may or may not have succeeded. /// <param name="value">The new value of the setting.</param>
/// </returns> /// <returns>A feedback sending result which may or may not have succeeded.</returns>
[Command("settings")] [Command("settings")]
[Description("Change settings for this server")] [Description("Change settings for this server")]
public async Task<Result> EditSettingsAsync( public async Task<Result> EditSettingsAsync(
[Description("настройка")] string setting, [Description("The setting whose value you want to change")]
[Description("значение")] string value) { string setting,
[Description("Setting value")] string value) {
if (!_context.TryGetContextIDs(out var guildId, out _, out _)) if (!_context.TryGetContextIDs(out var guildId, out _, out _))
return Result.FromError( return Result.FromError(
new ArgumentNullError(nameof(_context), "Unable to retrieve necessary IDs from command context")); new ArgumentNullError(nameof(_context), "Unable to retrieve necessary IDs from command context"));
@ -147,7 +143,7 @@ public class SettingsCommandGroup : CommandGroup {
.Append($" {Messages.SettingIsNow} ") .Append($" {Messages.SettingIsNow} ")
.Append(Markdown.InlineCode(value)); .Append(Markdown.InlineCode(value));
var embed = new EmbedBuilder().WithSmallTitle(Messages.SettingSuccessfulyChanged, currentUser) var embed = new EmbedBuilder().WithSmallTitle(Messages.SettingSuccessfullyChanged, currentUser)
.WithDescription(builder.ToString()) .WithDescription(builder.ToString())
.WithColour(ColorsList.Green) .WithColour(ColorsList.Green)
.Build(); .Build();

View file

@ -159,7 +159,7 @@ public static class Extensions {
builder.AppendLine(line.Text); builder.AppendLine(line.Text);
} }
return Markdown.BlockCode(builder.ToString().SanitizeForBlockCode(), "diff"); return InBlockCode(builder.ToString());
} }
public static string GetTag(this IUser user) { public static string GetTag(this IUser user) {

2195
Messages.Designer.cs generated

File diff suppressed because it is too large Load diff

View file

@ -549,8 +549,8 @@
<data name="SettingsListTitle" xml:space="preserve"> <data name="SettingsListTitle" xml:space="preserve">
<value>Boyfriend's Settings</value> <value>Boyfriend's Settings</value>
</data> </data>
<data name="SettingSuccessfulyChanged" xml:space="preserve"> <data name="SettingSuccessfullyChanged" xml:space="preserve">
<value>Setting successfuly changed</value> <value>Setting successfully changed</value>
</data> </data>
<data name="SettingNotChanged" xml:space="preserve"> <data name="SettingNotChanged" xml:space="preserve">
<value>Setting not changed</value> <value>Setting not changed</value>

View file

@ -549,7 +549,7 @@
<data name="SettingsListTitle" xml:space="preserve"> <data name="SettingsListTitle" xml:space="preserve">
<value>Настройки Boyfriend</value> <value>Настройки Boyfriend</value>
</data> </data>
<data name="SettingSuccessfulyChanged" xml:space="preserve"> <data name="SettingSuccessfullyChanged" xml:space="preserve">
<value>Настройка успешно изменена</value> <value>Настройка успешно изменена</value>
</data> </data>
<data name="SettingNotChanged" xml:space="preserve"> <data name="SettingNotChanged" xml:space="preserve">

View file

@ -549,7 +549,7 @@
<data name="SettingsListTitle" xml:space="preserve"> <data name="SettingsListTitle" xml:space="preserve">
<value>приколы Boyfriend</value> <value>приколы Boyfriend</value>
</data> </data>
<data name="SettingSuccessfulyChanged" xml:space="preserve"> <data name="SettingSuccessfullyChanged" xml:space="preserve">
<value>прикол редактирован</value> <value>прикол редактирован</value>
</data> </data>
<data name="SettingNotChanged" xml:space="preserve"> <data name="SettingNotChanged" xml:space="preserve">

View file

@ -43,6 +43,6 @@ the most effective way possible.
[JetBrains](https://www.jetbrains.com/), creators of [ReSharper](https://www.jetbrains.com/resharper) [JetBrains](https://www.jetbrains.com/), creators of [ReSharper](https://www.jetbrains.com/resharper)
and [Rider](https://www.jetbrains.com/rider), supports Boyfriend with one of and [Rider](https://www.jetbrains.com/rider), supports Boyfriend with one of
their [Open Source Licenses](https://jb.gg/OpenSourceSupport). their [Open Source Licenses](https://jb.gg/OpenSourceSupport).
Rider is the recommended IDE when working with Boyfriend, and most of the Boyfriend team uses it. Rider is the recommended IDE when working with Boyfriend, and everyone on the Boyfriend team uses it.
Additionally, ReSharper command-line tools made by JetBrains are used for status checks on pull requests to ensure code Additionally, ReSharper command-line tools made by JetBrains are used for status checks on pull requests to ensure code
quality even when not using ReSharper or Rider. quality even when not using ReSharper or Rider.