From ab94fa5ea6899505c8dbeef086fe8b63b25486c3 Mon Sep 17 00:00:00 2001 From: Cenngo Date: Sun, 17 Apr 2022 18:18:23 +0300 Subject: [PATCH] add withLocalizations parameter to rest methods --- .../Entities/Guilds/IGuild.cs | 2 +- .../SlashCommands/SlashCommandBuilder.cs | 96 ++++++++++--------- src/Discord.Net.Core/IDiscordClient.cs | 2 +- src/Discord.Net.Rest/BaseDiscordClient.cs | 4 +- src/Discord.Net.Rest/ClientHelper.cs | 8 +- src/Discord.Net.Rest/DiscordRestApiClient.cs | 12 ++- src/Discord.Net.Rest/DiscordRestClient.cs | 14 +-- .../Entities/Guilds/GuildHelper.cs | 6 +- .../Entities/Guilds/RestGuild.cs | 12 +-- .../Entities/Guilds/SocketGuild.cs | 9 +- 10 files changed, 85 insertions(+), 80 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs index b4625abbf..07c426f09 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs @@ -1147,7 +1147,7 @@ namespace Discord /// A task that represents the asynchronous get operation. The task result contains a read-only collection /// of application commands found within the guild. /// - Task> GetApplicationCommandsAsync(RequestOptions options = null); + Task> GetApplicationCommandsAsync(bool withLocalizations = false, RequestOptions options = null); /// /// Gets an application command within this guild with the specified id. diff --git a/src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandBuilder.cs b/src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandBuilder.cs index 9cec14839..061cf5bfa 100644 --- a/src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandBuilder.cs +++ b/src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandBuilder.cs @@ -34,18 +34,7 @@ namespace Discord get => _name; set { - Preconditions.NotNullOrEmpty(value, nameof(value)); - Preconditions.AtLeast(value.Length, 1, nameof(value)); - Preconditions.AtMost(value.Length, MaxNameLength, nameof(value)); - - // Discord updated the docs, this regex prevents special characters like @!$%(... etc, - // https://discord.com/developers/docs/interactions/slash-commands#applicationcommand - if (!Regex.IsMatch(value, @"^[\w-]{1,32}$")) - throw new ArgumentException("Command name cannot contain any special characters or whitespaces!", nameof(value)); - - if (value.Any(x => char.IsUpper(x))) - throw new FormatException("Name cannot contain any uppercase characters."); - + EnsureValidCommandName(value); _name = value; } } @@ -58,10 +47,7 @@ namespace Discord get => _description; set { - Preconditions.NotNullOrEmpty(value, nameof(Description)); - Preconditions.AtLeast(value.Length, 1, nameof(Description)); - Preconditions.AtMost(value.Length, MaxDescriptionLength, nameof(Description)); - + EnsureValidCommandDescription(value); _description = value; } } @@ -268,10 +254,7 @@ namespace Discord 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)); - if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) - throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(name)); + EnsureValidCommandName(name); } _nameLocalizations = new Dictionary(nameLocalizations); @@ -288,8 +271,7 @@ namespace Discord 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)); + EnsureValidCommandDescription(description); } _descriptionLocalizations = new Dictionary(descriptionLocalizations); @@ -301,12 +283,9 @@ namespace Discord 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)); - if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) - throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(name)); + EnsureValidCommandName(name); - _descriptionLocalizations ??= new(); + _nameLocalizations ??= new(); _nameLocalizations.Add(locale, name); return this; @@ -317,14 +296,35 @@ namespace Discord 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)); + EnsureValidCommandDescription(description); _descriptionLocalizations ??= new(); _descriptionLocalizations.Add(locale, description); return this; } + + internal static void EnsureValidCommandName(string name) + { + Preconditions.NotNullOrEmpty(name, nameof(name)); + Preconditions.AtLeast(name.Length, 1, nameof(name)); + Preconditions.AtMost(name.Length, MaxNameLength, nameof(name)); + + // Discord updated the docs, this regex prevents special characters like @!$%(... etc, + // https://discord.com/developers/docs/interactions/slash-commands#applicationcommand + if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) + throw new ArgumentException("Command name cannot contain any special characters or whitespaces!", nameof(name)); + + if (name.Any(x => char.IsUpper(x))) + throw new FormatException("Name cannot contain any uppercase characters."); + } + + internal static void EnsureValidCommandDescription(string description) + { + Preconditions.NotNullOrEmpty(description, nameof(description)); + Preconditions.AtLeast(description.Length, 1, nameof(description)); + Preconditions.AtMost(description.Length, MaxDescriptionLength, nameof(description)); + } } /// @@ -357,10 +357,7 @@ namespace Discord { if (value != null) { - Preconditions.AtLeast(value.Length, 1, nameof(value)); - Preconditions.AtMost(value.Length, SlashCommandBuilder.MaxNameLength, nameof(value)); - if (!Regex.IsMatch(value, @"^[\w-]{1,32}$")) - throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(value)); + EnsureValidCommandOptionName(value); } _name = value; @@ -377,8 +374,7 @@ namespace Discord { if (value != null) { - Preconditions.AtLeast(value.Length, 1, nameof(value)); - Preconditions.AtMost(value.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(value)); + EnsureValidCommandOptionDescription(value); } _description = value; @@ -752,10 +748,7 @@ namespace Discord 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)); - if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) - throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(name)); + EnsureValidCommandOptionName(name); } _nameLocalizations = new Dictionary(nameLocalizations); @@ -772,8 +765,7 @@ namespace Discord 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)); + EnsureValidCommandOptionDescription(description); } _descriptionLocalizations = new Dictionary(descriptionLocalizations); @@ -785,10 +777,7 @@ namespace Discord 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)); - if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) - throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(name)); + EnsureValidCommandOptionName(name); _descriptionLocalizations ??= new(); _nameLocalizations.Add(locale, name); @@ -801,13 +790,26 @@ namespace Discord 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)); + EnsureValidCommandOptionDescription(description); _descriptionLocalizations ??= new(); _descriptionLocalizations.Add(locale, description); return this; } + + private static void EnsureValidCommandOptionName(string name) + { + Preconditions.AtLeast(name.Length, 1, nameof(name)); + Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name)); + if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) + throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(name)); + } + + private static void EnsureValidCommandOptionDescription(string description) + { + Preconditions.AtLeast(description.Length, 1, nameof(description)); + Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description)); + } } } diff --git a/src/Discord.Net.Core/IDiscordClient.cs b/src/Discord.Net.Core/IDiscordClient.cs index 14e156769..939c04f89 100644 --- a/src/Discord.Net.Core/IDiscordClient.cs +++ b/src/Discord.Net.Core/IDiscordClient.cs @@ -160,7 +160,7 @@ namespace Discord /// A task that represents the asynchronous get operation. The task result contains a read-only collection of global /// application commands. /// - Task> GetGlobalApplicationCommandsAsync(RequestOptions options = null); + Task> GetGlobalApplicationCommandsAsync(bool withLocalizations = false, RequestOptions options = null); /// /// Creates a global application command. diff --git a/src/Discord.Net.Rest/BaseDiscordClient.cs b/src/Discord.Net.Rest/BaseDiscordClient.cs index 2bf08e3c7..fd429a257 100644 --- a/src/Discord.Net.Rest/BaseDiscordClient.cs +++ b/src/Discord.Net.Rest/BaseDiscordClient.cs @@ -241,7 +241,7 @@ namespace Discord.Rest => Task.FromResult(null); /// - Task> IDiscordClient.GetGlobalApplicationCommandsAsync(RequestOptions options) + Task> IDiscordClient.GetGlobalApplicationCommandsAsync(bool withLocalizations, RequestOptions options) => Task.FromResult>(ImmutableArray.Create()); Task IDiscordClient.CreateGlobalApplicationCommand(ApplicationCommandProperties properties, RequestOptions options) => Task.FromResult(null); @@ -255,6 +255,6 @@ namespace Discord.Rest /// Task IDiscordClient.StopAsync() => Task.Delay(0); - #endregion + #endregion } } diff --git a/src/Discord.Net.Rest/ClientHelper.cs b/src/Discord.Net.Rest/ClientHelper.cs index c6ad6a9fb..166e14de3 100644 --- a/src/Discord.Net.Rest/ClientHelper.cs +++ b/src/Discord.Net.Rest/ClientHelper.cs @@ -194,10 +194,10 @@ namespace Discord.Rest }; } - public static async Task> GetGlobalApplicationCommandsAsync(BaseDiscordClient client, + public static async Task> GetGlobalApplicationCommandsAsync(BaseDiscordClient client, bool withLocalizations = false, RequestOptions options = null) { - var response = await client.ApiClient.GetGlobalApplicationCommandsAsync(options).ConfigureAwait(false); + var response = await client.ApiClient.GetGlobalApplicationCommandsAsync(withLocalizations, options).ConfigureAwait(false); if (!response.Any()) return Array.Empty(); @@ -212,10 +212,10 @@ namespace Discord.Rest return model != null ? RestGlobalCommand.Create(client, model) : null; } - public static async Task> GetGuildApplicationCommandsAsync(BaseDiscordClient client, ulong guildId, + public static async Task> GetGuildApplicationCommandsAsync(BaseDiscordClient client, ulong guildId, bool withLocalizations = false, RequestOptions options = null) { - var response = await client.ApiClient.GetGuildApplicationCommandsAsync(guildId, options).ConfigureAwait(false); + var response = await client.ApiClient.GetGuildApplicationCommandsAsync(guildId, withLocalizations, options).ConfigureAwait(false); if (!response.Any()) return ImmutableArray.Create(); diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index 645e6711c..5fe9d922d 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -1188,11 +1188,12 @@ namespace Discord.API #endregion #region Interactions - public async Task GetGlobalApplicationCommandsAsync(RequestOptions options = null) + public async Task GetGlobalApplicationCommandsAsync(bool withLocalizations = false, RequestOptions options = null) { options = RequestOptions.CreateOrClone(options); - return await SendAsync("GET", () => $"applications/{CurrentApplicationId}/commands", new BucketIds(), options: options).ConfigureAwait(false); + return await SendAsync("GET", () => $"applications/{CurrentApplicationId}/commands?with_localizations={withLocalizations}", + new BucketIds(), options: options).ConfigureAwait(false); } public async Task GetGlobalApplicationCommandAsync(ulong id, RequestOptions options = null) @@ -1257,13 +1258,14 @@ namespace Discord.API return await SendJsonAsync("PUT", () => $"applications/{CurrentApplicationId}/commands", commands, new BucketIds(), options: options).ConfigureAwait(false); } - public async Task GetGuildApplicationCommandsAsync(ulong guildId, RequestOptions options = null) + public async Task GetGuildApplicationCommandsAsync(ulong guildId, bool withLocalizations = false, RequestOptions options = null) { options = RequestOptions.CreateOrClone(options); var bucket = new BucketIds(guildId: guildId); - return await SendAsync("GET", () => $"applications/{CurrentApplicationId}/guilds/{guildId}/commands", bucket, options: options).ConfigureAwait(false); + return await SendAsync("GET", () => $"applications/{CurrentApplicationId}/guilds/{guildId}/commands?with_localizations={withLocalizations}", + bucket, options: options).ConfigureAwait(false); } public async Task GetGuildApplicationCommandAsync(ulong guildId, ulong commandId, RequestOptions options = null) @@ -1400,7 +1402,7 @@ namespace Discord.API throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content)); options = RequestOptions.CreateOrClone(options); - + var ids = new BucketIds(); return await SendMultipartAsync("POST", () => $"webhooks/{CurrentApplicationId}/{token}?wait=true", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); } diff --git a/src/Discord.Net.Rest/DiscordRestClient.cs b/src/Discord.Net.Rest/DiscordRestClient.cs index b1948f80a..413aed4d7 100644 --- a/src/Discord.Net.Rest/DiscordRestClient.cs +++ b/src/Discord.Net.Rest/DiscordRestClient.cs @@ -25,7 +25,7 @@ namespace Discord.Rest /// Gets the logged-in user. /// public new RestSelfUser CurrentUser { get => base.CurrentUser as RestSelfUser; internal set => base.CurrentUser = value; } - + /// public DiscordRestClient() : this(new DiscordRestConfig()) { } /// @@ -197,10 +197,10 @@ namespace Discord.Rest => ClientHelper.CreateGlobalApplicationCommandAsync(this, properties, options); public Task CreateGuildCommand(ApplicationCommandProperties properties, ulong guildId, RequestOptions options = null) => ClientHelper.CreateGuildApplicationCommandAsync(this, guildId, properties, options); - public Task> GetGlobalApplicationCommands(RequestOptions options = null) - => ClientHelper.GetGlobalApplicationCommandsAsync(this, options); - public Task> GetGuildApplicationCommands(ulong guildId, RequestOptions options = null) - => ClientHelper.GetGuildApplicationCommandsAsync(this, guildId, options); + public Task> GetGlobalApplicationCommands(bool withLocalizations = false, RequestOptions options = null) + => ClientHelper.GetGlobalApplicationCommandsAsync(this, withLocalizations, options); + public Task> GetGuildApplicationCommands(ulong guildId, bool withLocalizations = false, RequestOptions options = null) + => ClientHelper.GetGuildApplicationCommandsAsync(this, guildId, withLocalizations, options); public Task> BulkOverwriteGlobalCommands(ApplicationCommandProperties[] commandProperties, RequestOptions options = null) => ClientHelper.BulkOverwriteGlobalApplicationCommandAsync(this, commandProperties, options); public Task> BulkOverwriteGuildCommands(ApplicationCommandProperties[] commandProperties, ulong guildId, RequestOptions options = null) @@ -311,8 +311,8 @@ namespace Discord.Rest => await GetWebhookAsync(id, options).ConfigureAwait(false); /// - async Task> IDiscordClient.GetGlobalApplicationCommandsAsync(RequestOptions options) - => await GetGlobalApplicationCommands(options).ConfigureAwait(false); + async Task> IDiscordClient.GetGlobalApplicationCommandsAsync(bool withLocalizations, RequestOptions options) + => await GetGlobalApplicationCommands(withLocalizations, options).ConfigureAwait(false); /// async Task IDiscordClient.GetGlobalApplicationCommandAsync(ulong id, RequestOptions options) => await ClientHelper.GetGlobalApplicationCommandAsync(this, id, options).ConfigureAwait(false); diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs index 7dbe20881..03554ab71 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs @@ -317,10 +317,10 @@ namespace Discord.Rest #endregion #region Interactions - public static async Task> GetSlashCommandsAsync(IGuild guild, BaseDiscordClient client, + public static async Task> GetSlashCommandsAsync(IGuild guild, BaseDiscordClient client, bool withLocalizations, RequestOptions options) { - var models = await client.ApiClient.GetGuildApplicationCommandsAsync(guild.Id, options); + var models = await client.ApiClient.GetGuildApplicationCommandsAsync(guild.Id, withLocalizations, options); return models.Select(x => RestGuildCommand.Create(client, x, guild.Id)).ToImmutableArray(); } public static async Task GetSlashCommandAsync(IGuild guild, ulong id, BaseDiscordClient client, @@ -866,7 +866,7 @@ namespace Discord.Rest if (endTime != null && endTime <= startTime) throw new ArgumentOutOfRangeException(nameof(endTime), $"{nameof(endTime)} cannot be before the start time"); - + var apiArgs = new CreateGuildScheduledEventParams() { ChannelId = channelId ?? Optional.Unspecified, diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs index d7ab65a55..57a3e9e54 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs @@ -316,8 +316,8 @@ namespace Discord.Rest /// A task that represents the asynchronous get operation. The task result contains a read-only collection of /// slash commands created by the current user. /// - public Task> GetSlashCommandsAsync(RequestOptions options = null) - => GuildHelper.GetSlashCommandsAsync(this, Discord, options); + public Task> GetSlashCommandsAsync(bool withLocalizations = false, RequestOptions options = null) + => GuildHelper.GetSlashCommandsAsync(this, Discord, withLocalizations, options); /// /// Gets a slash command in the current guild. @@ -932,8 +932,8 @@ namespace Discord.Rest /// A task that represents the asynchronous get operation. The task result contains a read-only collection /// of application commands found within the guild. /// - public async Task> GetApplicationCommandsAsync (RequestOptions options = null) - => await ClientHelper.GetGuildApplicationCommandsAsync(Discord, Id, options).ConfigureAwait(false); + public async Task> GetApplicationCommandsAsync (bool withLocalizations = false, RequestOptions options = null) + => await ClientHelper.GetGuildApplicationCommandsAsync(Discord, Id, withLocalizations, options).ConfigureAwait(false); /// /// Gets an application command within this guild with the specified id. /// @@ -1465,8 +1465,8 @@ namespace Discord.Rest async Task> IGuild.GetWebhooksAsync(RequestOptions options) => await GetWebhooksAsync(options).ConfigureAwait(false); /// - async Task> IGuild.GetApplicationCommandsAsync (RequestOptions options) - => await GetApplicationCommandsAsync(options).ConfigureAwait(false); + async Task> IGuild.GetApplicationCommandsAsync (bool withLocalizations, RequestOptions options) + => await GetApplicationCommandsAsync(withLocalizations, options).ConfigureAwait(false); /// async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, Image image, RequestOptions options) => await CreateStickerAsync(name, description, tags, image, options); diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index 47bd57552..52b977ca3 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -872,9 +872,10 @@ namespace Discord.WebSocket /// A task that represents the asynchronous get operation. The task result contains a read-only collection of /// slash commands created by the current user. /// - public async Task> GetApplicationCommandsAsync(RequestOptions options = null) + public async Task> GetApplicationCommandsAsync(bool withLocalizations = false, RequestOptions options = null) { - var commands = (await Discord.ApiClient.GetGuildApplicationCommandsAsync(Id, options)).Select(x => SocketApplicationCommand.Create(Discord, x, Id)); + var commands = (await Discord.ApiClient.GetGuildApplicationCommandsAsync(Id, withLocalizations, options)) + .Select(x => SocketApplicationCommand.Create(Discord, x, Id)); foreach (var command in commands) { @@ -1965,8 +1966,8 @@ namespace Discord.WebSocket async Task> IGuild.GetWebhooksAsync(RequestOptions options) => await GetWebhooksAsync(options).ConfigureAwait(false); /// - async Task> IGuild.GetApplicationCommandsAsync (RequestOptions options) - => await GetApplicationCommandsAsync(options).ConfigureAwait(false); + async Task> IGuild.GetApplicationCommandsAsync (bool withLocalizations, RequestOptions options) + => await GetApplicationCommandsAsync(withLocalizations, options).ConfigureAwait(false); /// async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, Image image, RequestOptions options) => await CreateStickerAsync(name, description, tags, image, options);