diff --git a/docs/guides/int_basics/application-commands/intro.md b/docs/guides/int_basics/application-commands/intro.md index f55d0a2fc..a59aca8f2 100644 --- a/docs/guides/int_basics/application-commands/intro.md +++ b/docs/guides/int_basics/application-commands/intro.md @@ -18,9 +18,6 @@ The name and description help users find your command among many others, and the Message and User commands are only a name, to the user. So try to make the name descriptive. They're accessed by right clicking (or long press, on mobile) a user or a message, respectively. -> [!IMPORTANT] -> Context menu commands are currently not supported on mobile. - All three varieties of application commands have both Global and Guild variants. Your global commands are available in every guild that adds your application. You can also make commands for a specific guild; they're only available in that guild. diff --git a/src/Discord.Net.Core/DiscordErrorCode.cs b/src/Discord.Net.Core/DiscordErrorCode.cs index 262252eab..60b7d20d8 100644 --- a/src/Discord.Net.Core/DiscordErrorCode.cs +++ b/src/Discord.Net.Core/DiscordErrorCode.cs @@ -172,13 +172,14 @@ namespace Discord ServerRequiresMonetization = 50097, ServerRequiresBoosts = 50101, RequestBodyContainsInvalidJSON = 50109, - #endregion - - #region 2FA (60XXX) + FailedToResizeAssetBelowTheMaximumSize = 50138, OwnershipCannotBeTransferredToABotUser = 50132, AssetResizeBelowTheMaximumSize= 50138, UploadedFileNotFound = 50146, MissingPermissionToSendThisSticker = 50600, + #endregion + + #region 2FA (60XXX) Requires2FA = 60003, #endregion diff --git a/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs index df33cfe1d..17e836e21 100644 --- a/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs +++ b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs @@ -106,13 +106,17 @@ namespace Discord get => _nameLocalizations; set { - foreach (var (locale, name) in value) + if (value != null) { - if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) - throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); + foreach (var (locale, name) in value) + { + if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) + throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); - EnsureValidOptionName(name); + EnsureValidOptionName(name); + } } + _nameLocalizations = value; } } @@ -126,13 +130,17 @@ namespace Discord get => _descriptionLocalizations; set { - foreach (var (locale, description) in value) + if (value != null) { - if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) - throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); + foreach (var (locale, description) in value) + { + if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) + throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); - EnsureValidOptionDescription(description); + EnsureValidOptionDescription(description); + } } + _descriptionLocalizations = value; } } diff --git a/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionChoice.cs b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionChoice.cs index 8f1ecc6d2..2289b412d 100644 --- a/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionChoice.cs +++ b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionChoice.cs @@ -55,18 +55,21 @@ namespace Discord get => _nameLocalizations; set { - foreach (var (locale, name) in value) + if (value != null) { - if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) - throw new ArgumentException("Key values of the dictionary must be valid language codes."); - - switch (name.Length) + foreach (var (locale, name) in value) { - case > 100: - throw new ArgumentOutOfRangeException(nameof(value), - "Name length must be less than or equal to 100."); - case 0: - throw new ArgumentOutOfRangeException(nameof(value), "Name length must at least 1."); + if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) + throw new ArgumentException("Key values of the dictionary must be valid language codes."); + + switch (name.Length) + { + case > 100: + throw new ArgumentOutOfRangeException(nameof(value), + "Name length must be less than or equal to 100."); + case 0: + throw new ArgumentOutOfRangeException(nameof(value), "Name length must at least 1."); + } } } diff --git a/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandProperties.cs b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandProperties.cs index 98e050df9..0c1c628cd 100644 --- a/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandProperties.cs +++ b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandProperties.cs @@ -35,17 +35,21 @@ namespace Discord get => _nameLocalizations; set { - foreach (var (locale, name) in value) + if (value != null) { - if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) - throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); + foreach (var (locale, name) in value) + { + if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) + throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); - Preconditions.AtLeast(name.Length, 1, nameof(name)); - Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name)); + Preconditions.AtLeast(name.Length, 1, nameof(name)); + Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name)); - if (Type == ApplicationCommandType.Slash && !Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$")) - throw new ArgumentException(@"Name must match the regex ^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$", nameof(name)); + if (Type == ApplicationCommandType.Slash && !Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$")) + throw new ArgumentException(@"Name must match the regex ^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$", nameof(name)); + } } + _nameLocalizations = value; } } @@ -58,14 +62,18 @@ namespace Discord get => _descriptionLocalizations; set { - foreach (var (locale, description) in value) + if (value != null) { - if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) - throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); + foreach (var (locale, description) in value) + { + if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) + throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); - Preconditions.AtLeast(description.Length, 1, nameof(description)); - Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description)); + Preconditions.AtLeast(description.Length, 1, nameof(description)); + Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description)); + } } + _descriptionLocalizations = value; } } diff --git a/test/Discord.Net.Tests.Unit/CommandBuilderTests.cs b/test/Discord.Net.Tests.Unit/CommandBuilderTests.cs new file mode 100644 index 000000000..e122f9cdd --- /dev/null +++ b/test/Discord.Net.Tests.Unit/CommandBuilderTests.cs @@ -0,0 +1,37 @@ +using System; +using Discord; +using Xunit; + +namespace Discord; + +public class CommandBuilderTests +{ + [Fact] + public void BuildSimpleSlashCommand() + { + var command = new SlashCommandBuilder() + .WithName("command") + .WithDescription("description") + .AddOption( + "option1", + ApplicationCommandOptionType.String, + "option1 description", + isRequired: true, + choices: new [] + { + new ApplicationCommandOptionChoiceProperties() + { + Name = "choice1", Value = "1" + } + }) + .AddOptions(new SlashCommandOptionBuilder() + .WithName("option2") + .WithDescription("option2 description") + .WithType(ApplicationCommandOptionType.String) + .WithRequired(true) + .AddChannelType(ChannelType.Text) + .AddChoice("choice1", "1") + .AddChoice("choice2", "2")); + command.Build(); + } +}