From 8e507915e38fc15ae1f6c985e798a49f2b52c7ea Mon Sep 17 00:00:00 2001 From: quin lynch Date: Tue, 6 Jul 2021 19:12:21 -0300 Subject: [PATCH] Finished command permissions as well as bug fixes --- src/Discord.Net.Core/Discord.Net.Core.xml | 38 ++- .../Entities/Guilds/PermissionTarget.cs | 4 +- .../Interactions/IApplicationCommand.cs | 10 +- .../Interactions/SlashCommandBuilder.cs | 18 ++ .../ApplicationCommandPermissions.cs | 24 +- .../GuildApplicationCommandPermissions.cs | 11 +- .../API/Common/ApplicationCommand.cs | 2 + .../Common/ApplicationCommandPermissions.cs | 2 +- .../GuildApplicationCommandPermissions.cs | 8 +- ...odifyGuildApplicationCommandPermissions.cs | 2 +- src/Discord.Net.Rest/ClientHelper.cs | 3 +- src/Discord.Net.Rest/Discord.Net.Rest.csproj | 2 +- src/Discord.Net.Rest/Discord.Net.Rest.xml | 59 +++++ src/Discord.Net.Rest/DiscordRestApiClient.cs | 151 +++++------ src/Discord.Net.Rest/DiscordRestClient.cs | 9 + .../Entities/Guilds/GuildHelper.cs | 14 ++ .../Entities/Guilds/RestGuild.cs | 25 +- .../Interactions/InteractionHelper.cs | 237 +++++++++++++++--- .../Interactions/RestApplicationCommand.cs | 9 +- .../Entities/Interactions/RestGuildCommand.cs | 38 ++- .../ApplicationCommandCreatedUpdatedEvent.cs | 3 + .../Discord.Net.WebSocket.xml | 27 ++ .../Entities/Guilds/SocketGuild.cs | 24 ++ .../SocketApplicationCommand.cs | 11 +- .../Slash Commands/SocketSlashCommandData.cs | 17 +- src/Discord.Net/Discord.Net.nuspec | 16 +- 26 files changed, 574 insertions(+), 190 deletions(-) diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml index 775d0b3cc..f6ad03d32 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.xml +++ b/src/Discord.Net.Core/Discord.Net.Core.xml @@ -3967,11 +3967,6 @@ The base command model that belongs to an application. see - - - Gets the unique id of the command. - - Gets the unique id of the parent application. @@ -3987,6 +3982,11 @@ The description of the command. + + + Whether the command is enabled by default when the app is added to a guild. + + If the option is a subcommand or subcommand group type, this nested options will be the parameters. @@ -4886,6 +4886,11 @@ Gets or sets the options for this command. + + + Whether the command is enabled by default when the app is added to a guild + + Build the current builder into a class. @@ -4908,6 +4913,13 @@ The description of this command. The current builder. + + + Sets the default permission of the current command. + + The default permission value to set. + The current builder. + Adds an option to the current slash command. @@ -7243,17 +7255,17 @@ Application command permissions allow you to enable or disable commands for specific users or roles within a guild. - + The id of the role or user. - + The target of this permission. - + to allow, otherwise . @@ -7525,27 +7537,27 @@ Creates a new from this one, changing the provided non-null permissions. - + Returned when fetching the permissions for a command in a guild. - + The id of the command. - + The id of the application the command belongs to. - + The id of the guild. - + The permissions for the command in the guild. diff --git a/src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs b/src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs index fb759e4c5..39e7c81f2 100644 --- a/src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs +++ b/src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs @@ -8,10 +8,10 @@ namespace Discord /// /// The target of the permission is a role. /// - Role = 0, + Role = 1, /// /// The target of the permission is a user. /// - User = 1, + User = 2, } } diff --git a/src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs index cf1395328..eb61c539f 100644 --- a/src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs +++ b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs @@ -11,11 +11,6 @@ namespace Discord /// public interface IApplicationCommand : ISnowflakeEntity { - /// - /// Gets the unique id of the command. - /// - ulong Id { get; } - /// /// Gets the unique id of the parent application. /// @@ -31,6 +26,11 @@ namespace Discord /// string Description { get; } + /// + /// Whether the command is enabled by default when the app is added to a guild. + /// + bool DefaultPermission { get; } + /// /// If the option is a subcommand or subcommand group type, this nested options will be the parameters. /// diff --git a/src/Discord.Net.Core/Entities/Interactions/SlashCommandBuilder.cs b/src/Discord.Net.Core/Entities/Interactions/SlashCommandBuilder.cs index 948527f29..bd6337f89 100644 --- a/src/Discord.Net.Core/Entities/Interactions/SlashCommandBuilder.cs +++ b/src/Discord.Net.Core/Entities/Interactions/SlashCommandBuilder.cs @@ -82,6 +82,12 @@ namespace Discord _options = value; } } + + /// + /// Whether the command is enabled by default when the app is added to a guild + /// + public bool DefaultPermission { get; set; } = true; + private string _name { get; set; } private string _description { get; set; } private List _options { get; set; } @@ -96,6 +102,7 @@ namespace Discord { Name = this.Name, Description = this.Description, + DefaultPermission = this.DefaultPermission }; if (this.Options != null && this.Options.Any()) @@ -135,6 +142,17 @@ namespace Discord return this; } + /// + /// Sets the default permission of the current command. + /// + /// The default permission value to set. + /// The current builder. + public SlashCommandBuilder WithDefaultPermission(bool value) + { + this.DefaultPermission = value; + return this; + } + /// /// Adds an option to the current slash command. /// diff --git a/src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissions.cs b/src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissions.cs index 86dbd5790..f87613ab8 100644 --- a/src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissions.cs +++ b/src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissions.cs @@ -8,17 +8,17 @@ namespace Discord /// /// The id of the role or user. /// - public ulong Id { get; } + public ulong TargetId { get; } /// /// The target of this permission. /// - public PermissionTarget Type { get; } + public PermissionTarget TargetType { get; } /// /// to allow, otherwise . /// - public bool Value { get; } + public bool Permission { get; } internal ApplicationCommandPermission() { } @@ -30,9 +30,9 @@ namespace Discord /// The value of this permission. public ApplicationCommandPermission(ulong targetId, PermissionTarget targetType, bool allow) { - this.Id = targetId; - this.Type = targetType; - this.Value = allow; + this.TargetId = targetId; + this.TargetType = targetType; + this.Permission = allow; } /// @@ -42,9 +42,9 @@ namespace Discord /// The value of this permission. public ApplicationCommandPermission(IUser target, bool allow) { - this.Id = target.Id; - this.Value = allow; - this.Type = PermissionTarget.User; + this.TargetId = target.Id; + this.Permission = allow; + this.TargetType = PermissionTarget.User; } /// @@ -54,9 +54,9 @@ namespace Discord /// The value of this permission. public ApplicationCommandPermission(IRole target, bool allow) { - this.Id = target.Id; - this.Value = allow; - this.Type = PermissionTarget.Role; + this.TargetId = target.Id; + this.Permission = allow; + this.TargetType = PermissionTarget.Role; } } } diff --git a/src/Discord.Net.Core/Entities/Permissions/GuildApplicationCommandPermissions.cs b/src/Discord.Net.Core/Entities/Permissions/GuildApplicationCommandPermissions.cs index c91bfd59e..5145f5dc6 100644 --- a/src/Discord.Net.Core/Entities/Permissions/GuildApplicationCommandPermissions.cs +++ b/src/Discord.Net.Core/Entities/Permissions/GuildApplicationCommandPermissions.cs @@ -9,12 +9,13 @@ namespace Discord /// /// Returned when fetching the permissions for a command in a guild. /// - public class GuildApplicationCommandPermissions + public class GuildApplicationCommandPermission + { /// /// The id of the command. /// - public ulong Id { get; } + public ulong CommandId { get; } /// /// The id of the application the command belongs to. @@ -31,12 +32,12 @@ namespace Discord /// public IReadOnlyCollection Permissions { get; } - internal GuildApplicationCommandPermissions(ulong id, ulong appId, ulong guildId, List permissions) + internal GuildApplicationCommandPermission(ulong commandId, ulong appId, ulong guildId, ApplicationCommandPermission[] permissions) { - this.Id = id; + this.CommandId = commandId; this.ApplicationId = appId; this.GuildId = guildId; - this.Permissions = permissions.ToReadOnlyCollection(); + this.Permissions = permissions; } } } diff --git a/src/Discord.Net.Rest/API/Common/ApplicationCommand.cs b/src/Discord.Net.Rest/API/Common/ApplicationCommand.cs index f42837450..39c40a1ee 100644 --- a/src/Discord.Net.Rest/API/Common/ApplicationCommand.cs +++ b/src/Discord.Net.Rest/API/Common/ApplicationCommand.cs @@ -19,5 +19,7 @@ namespace Discord.API public string Description { get; set; } [JsonProperty("options")] public Optional Options { get; set; } + [JsonProperty("default_permission")] + public Optional DefaultPermissions { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Common/ApplicationCommandPermissions.cs b/src/Discord.Net.Rest/API/Common/ApplicationCommandPermissions.cs index 105913adc..a4a4ae074 100644 --- a/src/Discord.Net.Rest/API/Common/ApplicationCommandPermissions.cs +++ b/src/Discord.Net.Rest/API/Common/ApplicationCommandPermissions.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace Discord.API { - public class ApplicationCommandPermissions + internal class ApplicationCommandPermissions { [JsonProperty("id")] public ulong Id { get; set; } diff --git a/src/Discord.Net.Rest/API/Common/GuildApplicationCommandPermissions.cs b/src/Discord.Net.Rest/API/Common/GuildApplicationCommandPermissions.cs index f64c14fff..3ab5ef650 100644 --- a/src/Discord.Net.Rest/API/Common/GuildApplicationCommandPermissions.cs +++ b/src/Discord.Net.Rest/API/Common/GuildApplicationCommandPermissions.cs @@ -7,16 +7,16 @@ using System.Threading.Tasks; namespace Discord.API { - public class GuildApplicationCommandPermission + internal class GuildApplicationCommandPermission { [JsonProperty("id")] - public ulong Id { get; } + public ulong Id { get; set; } [JsonProperty("application_id")] - public ulong ApplicationId { get; } + public ulong ApplicationId { get; set; } [JsonProperty("guild_id")] - public ulong GuildId { get; } + public ulong GuildId { get; set; } [JsonProperty("permissions")] public API.ApplicationCommandPermissions[] Permissions { get; set; } diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissions.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissions.cs index 0d1792c94..5e42ee4c4 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissions.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissions.cs @@ -13,6 +13,6 @@ namespace Discord.API.Rest public ulong Id { get; set; } [JsonProperty("permissions")] - public ApplicationCommandPermission[] Permissions { get; set; } + public ApplicationCommandPermissions[] Permissions { get; set; } } } diff --git a/src/Discord.Net.Rest/ClientHelper.cs b/src/Discord.Net.Rest/ClientHelper.cs index 7bb358775..0161483c9 100644 --- a/src/Discord.Net.Rest/ClientHelper.cs +++ b/src/Discord.Net.Rest/ClientHelper.cs @@ -206,7 +206,7 @@ namespace Discord.Rest public static async Task> GetGuildApplicationCommands(BaseDiscordClient client, ulong guildId, RequestOptions options) { - var response = await client.ApiClient.GetGuildApplicationCommandAsync(guildId, options).ConfigureAwait(false); + var response = await client.ApiClient.GetGuildApplicationCommandsAsync(guildId, options).ConfigureAwait(false); if (!response.Any()) return new RestGuildCommand[0].ToImmutableArray(); @@ -214,6 +214,7 @@ namespace Discord.Rest return response.Select(x => RestGuildCommand.Create(client, x, guildId)).ToImmutableArray(); } + public static Task AddRoleAsync(BaseDiscordClient client, ulong guildId, ulong userId, ulong roleId, RequestOptions options = null) => client.ApiClient.AddRoleAsync(guildId, userId, roleId, options); diff --git a/src/Discord.Net.Rest/Discord.Net.Rest.csproj b/src/Discord.Net.Rest/Discord.Net.Rest.csproj index f942fa976..c071b7342 100644 --- a/src/Discord.Net.Rest/Discord.Net.Rest.csproj +++ b/src/Discord.Net.Rest/Discord.Net.Rest.csproj @@ -9,7 +9,7 @@ netstandard2.0;netstandard2.1 Temporary.png https://github.com/Discord-Net-Labs/Discord.Net-Labs - 2.4.1 + 2.4.2 Discord.Net.Labs.Rest https://github.com/Discord-Net-Labs/Discord.Net-Labs 2.3.4 diff --git a/src/Discord.Net.Rest/Discord.Net.Rest.xml b/src/Discord.Net.Rest/Discord.Net.Rest.xml index 35622a349..5a70ac05f 100644 --- a/src/Discord.Net.Rest/Discord.Net.Rest.xml +++ b/src/Discord.Net.Rest/Discord.Net.Rest.xml @@ -2740,6 +2740,27 @@ + + + Gets a collection of slash commands created by the current user in this guild. + + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains a read-only collection of + slash commands created by the current user. + + + + + Gets a slash command in the current guild. + + The unique identifier of the slash command. + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains a + slash command created by the current user. + + Gets a collection of all users banned in this guild. @@ -3378,6 +3399,9 @@ + + + The options of this command. @@ -3391,6 +3415,9 @@ + + + Represents a Rest-based implementation of . @@ -3488,6 +3515,38 @@ The modified command + + + Gets this commands permissions inside of the current guild. + + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains a + object defining the permissions of the current slash command. + + + + + Modifies the current command permissions for this guild command. + + The permissions to overwrite. + The options to be used when sending the request. + + A task that represents the asynchronous modification operation. The task result contains a + object containing the modified permissions. + + + + + Gets the guild that this slash command resides in. + + if you want the approximate member and presence counts for the guild, otherwise . + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains a + . + + diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index 60f0bcc32..21e74b4bf 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -827,54 +827,14 @@ namespace Discord.API options = RequestOptions.CreateOrClone(options); - try - { - return await SendJsonAsync("POST", () => $"applications/{this.CurrentUserId}/commands", command, new BucketIds(), options: options).ConfigureAwait(false); - } - catch (HttpException x) - { - if (x.HttpCode == HttpStatusCode.BadRequest) - { - var json = (x.Request as JsonRestRequest).Json; - throw new ApplicationCommandException(json, x); - } - // Re-throw the http exception - throw; - } + return await TrySendApplicationCommand(SendJsonAsync("POST", () => $"applications/{this.CurrentUserId}/commands", command, new BucketIds(), options: options)).ConfigureAwait(false); } public async Task ModifyGlobalApplicationCommandAsync(ModifyApplicationCommandParams command, ulong commandId, RequestOptions options = null) { - Preconditions.NotNull(command, nameof(command)); - - if (command.Name.IsSpecified) - { - Preconditions.AtMost(command.Name.Value.Length, 32, nameof(command.Name)); - Preconditions.AtLeast(command.Name.Value.Length, 3, nameof(command.Name)); - } - if (command.Description.IsSpecified) - { - Preconditions.AtMost(command.Description.Value.Length, 100, nameof(command.Description)); - Preconditions.AtLeast(command.Description.Value.Length, 1, nameof(command.Description)); - } - options = RequestOptions.CreateOrClone(options); - try - { - return await SendJsonAsync("PATCH", () => $"applications/{this.CurrentUserId}/commands/{commandId}", command, new BucketIds(), options: options).ConfigureAwait(false); - } - catch (HttpException x) - { - if (x.HttpCode == HttpStatusCode.BadRequest) - { - var json = (x.Request as JsonRestRequest).Json; - throw new ApplicationCommandException(json, x); - } - - // Re-throw the http exception - throw; - } + return await TrySendApplicationCommand(SendJsonAsync("PATCH", () => $"applications/{this.CurrentUserId}/commands/{commandId}", command, new BucketIds(), options: options)).ConfigureAwait(false); } public async Task DeleteGlobalApplicationCommandAsync(ulong commandId, RequestOptions options = null) { @@ -883,7 +843,14 @@ namespace Discord.API await SendAsync("DELETE", () => $"applications/{this.CurrentUserId}/commands/{commandId}", new BucketIds(), options: options).ConfigureAwait(false); } - public async Task GetGuildApplicationCommandAsync(ulong guildId, RequestOptions options = null) + public async Task BulkOverwriteGlobalApplicationCommands(CreateApplicationCommandParams[] commands, RequestOptions options = null) + { + options = RequestOptions.CreateOrClone(options); + + return await TrySendApplicationCommand(SendJsonAsync("PUT", () => $"applications/{this.CurrentUserId}/commands", commands, new BucketIds(), options: options)).ConfigureAwait(false); + } + + public async Task GetGuildApplicationCommandsAsync(ulong guildId, RequestOptions options = null) { options = RequestOptions.CreateOrClone(options); @@ -891,49 +858,27 @@ namespace Discord.API return await SendAsync("GET", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", bucket, options: options).ConfigureAwait(false); } - public async Task CreateGuildApplicationCommandAsync(CreateApplicationCommandParams command, ulong guildId, RequestOptions options = null) + + public async Task GetGuildApplicationCommandAsync(ulong guildId, ulong commandId, RequestOptions options = null) { - Preconditions.NotNull(command, nameof(command)); - Preconditions.AtMost(command.Name.Length, 32, nameof(command.Name)); - Preconditions.AtLeast(command.Name.Length, 3, nameof(command.Name)); - Preconditions.AtMost(command.Description.Length, 100, nameof(command.Description)); - Preconditions.AtLeast(command.Description.Length, 1, nameof(command.Description)); + options = RequestOptions.CreateOrClone(options); + var bucket = new BucketIds(guildId: guildId); + + return await SendAsync("GET", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}", bucket, options: options); + } + + public async Task CreateGuildApplicationCommandAsync(CreateApplicationCommandParams command, ulong guildId, RequestOptions options = null) + { options = RequestOptions.CreateOrClone(options); var bucket = new BucketIds(guildId: guildId); - try - { - return await SendJsonAsync("POST", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", command, bucket, options: options).ConfigureAwait(false); - } - catch (HttpException x) - { - if (x.HttpCode == HttpStatusCode.BadRequest) - { - var json = (x.Request as JsonRestRequest).Json; - throw new ApplicationCommandException(json, x); - } + return await TrySendApplicationCommand(SendJsonAsync("POST", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", command, bucket, options: options)).ConfigureAwait(false); - // Re-throw the http exception - throw; - } } public async Task ModifyGuildApplicationCommandAsync(ModifyApplicationCommandParams command, ulong guildId, ulong commandId, RequestOptions options = null) { - Preconditions.NotNull(command, nameof(command)); - - if (command.Name.IsSpecified) - { - Preconditions.AtMost(command.Name.Value.Length, 32, nameof(command.Name)); - Preconditions.AtLeast(command.Name.Value.Length, 3, nameof(command.Name)); - } - if (command.Description.IsSpecified) - { - Preconditions.AtMost(command.Description.Value.Length, 100, nameof(command.Description)); - Preconditions.AtLeast(command.Description.Value.Length, 1, nameof(command.Description)); - } - options = RequestOptions.CreateOrClone(options); var bucket = new BucketIds(guildId: guildId); @@ -963,6 +908,15 @@ namespace Discord.API await SendAsync("DELETE", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}", bucket, options: options).ConfigureAwait(false); } + public async Task BulkOverwriteGuildApplicationCommands(ulong guildId, CreateApplicationCommandParams[] commands, RequestOptions options = null) + { + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(guildId: guildId); + + return await TrySendApplicationCommand(SendJsonAsync("PUT", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", commands, bucket, options: options)).ConfigureAwait(false); + } + //Interaction Responses public async Task CreateInteractionResponse(InteractionResponse response, ulong interactionId, string interactionToken, RequestOptions options = null) { @@ -971,7 +925,7 @@ namespace Discord.API options = RequestOptions.CreateOrClone(options); - await SendJsonAsync("POST", () => $"interactions/{interactionId}/{interactionToken}/callback", response, new BucketIds(), options: options); + await SendJsonAsync("POST", () => $"interactions/{interactionId}/{interactionToken}/callback", response, new BucketIds(), options: options); } public async Task GetInteractionResponse(string interactionToken, RequestOptions options = null) { @@ -1037,7 +991,7 @@ namespace Discord.API options = RequestOptions.CreateOrClone(options); - return await SendAsync("GET", () => $"/applications/{this.CurrentUserId}/guilds/{guildId}/commands/permissions", new BucketIds(), options: options).ConfigureAwait(false); + return await SendAsync("GET", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/permissions", new BucketIds(), options: options).ConfigureAwait(false); } public async Task GetGuildApplicationCommandPermission(ulong guildId, ulong commandId, RequestOptions options = null) @@ -1047,37 +1001,27 @@ namespace Discord.API options = RequestOptions.CreateOrClone(options); - return await SendAsync("GET", () => $"/applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}/permissions", new BucketIds(), options: options).ConfigureAwait(false); + return await SendAsync("GET", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}/permissions", new BucketIds(), options: options).ConfigureAwait(false); } - public async Task ModifyApplicationCommandPermissions(ApplicationCommandPermissions[] permissions, ulong guildId, ulong commandId, RequestOptions options = null) + public async Task ModifyApplicationCommandPermissions(ApplicationCommandPermissions[] permissions, ulong guildId, ulong commandId, RequestOptions options = null) { Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotEqual(commandId, 0, nameof(commandId)); options = RequestOptions.CreateOrClone(options); - await SendJsonAsync("PUT", () => $"/applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}/permissions", permissions, new BucketIds(), options: options).ConfigureAwait(false); + return await SendJsonAsync("PUT", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}/permissions", permissions, new BucketIds(), options: options).ConfigureAwait(false); } - public async Task BatchModifyApplicationCommandPermissions(ModifyGuildApplicationCommandPermissions[] permissions, ulong guildId, RequestOptions options = null) + public async Task> BatchModifyApplicationCommandPermissions(ModifyGuildApplicationCommandPermissions[] permissions, ulong guildId, RequestOptions options = null) { Preconditions.NotEqual(guildId, 0, nameof(guildId)); Preconditions.NotNull(permissions, nameof(permissions)); options = RequestOptions.CreateOrClone(options); - await SendJsonAsync("PUT", () => $"/applications/{this.CurrentUserId}/guilds/{guildId}/commands/premissions", permissions, new BucketIds(), options: options).ConfigureAwait(false); - } - - public async Task BulkOverrideGuildApplicationCommand(API.ApplicationCommand[] commands, ulong guildId, RequestOptions options = null) - { - Preconditions.NotEqual(guildId, 0, nameof(guildId)); - Preconditions.NotNull(commands, nameof(commands)); - - options = RequestOptions.CreateOrClone(options); - - await SendJsonAsync("PUT", () => $"/applications/{this.CurrentUserId}/guilds/{guildId}/commands", commands, new BucketIds(), options: options).ConfigureAwait(false); + return await SendJsonAsync("PUT", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/permissions", permissions, new BucketIds(), options: options).ConfigureAwait(false); } //Guilds @@ -1772,6 +1716,27 @@ namespace Discord.API return _serializer.Deserialize(reader); } + protected async Task TrySendApplicationCommand(Task sendTask) + { + var result = await sendTask.ConfigureAwait(false); + + if (sendTask.Exception != null) + { + if (sendTask.Exception.InnerException is HttpException x) + { + if (x.HttpCode == HttpStatusCode.BadRequest) + { + var json = (x.Request as JsonRestRequest).Json; + throw new ApplicationCommandException(json, x); + } + } + + throw sendTask.Exception; + } + else + return result; + } + internal class BucketIds { public ulong GuildId { get; internal set; } diff --git a/src/Discord.Net.Rest/DiscordRestClient.cs b/src/Discord.Net.Rest/DiscordRestClient.cs index 5ac18ff57..0f93c3f65 100644 --- a/src/Discord.Net.Rest/DiscordRestClient.cs +++ b/src/Discord.Net.Rest/DiscordRestClient.cs @@ -106,6 +106,7 @@ namespace Discord.Rest => ClientHelper.GetVoiceRegionAsync(this, id, options); public Task GetWebhookAsync(ulong id, RequestOptions options = null) => ClientHelper.GetWebhookAsync(this, id, options); + public Task CreateGlobalCommand(SlashCommandCreationProperties properties, RequestOptions options = null) => InteractionHelper.CreateGlobalCommand(this, properties, options); public Task CreateGlobalCommand(Action func, RequestOptions options = null) @@ -118,6 +119,14 @@ namespace Discord.Rest => ClientHelper.GetGlobalApplicationCommands(this, options); public Task> GetGuildApplicationCommands(ulong guildId, RequestOptions options = null) => ClientHelper.GetGuildApplicationCommands(this, guildId, options); + public Task> BulkOverwriteGlobalCommands(SlashCommandCreationProperties[] commandProperties, RequestOptions options = null) + => InteractionHelper.BulkOverwriteGlobalCommands(this, commandProperties, options); + public Task> BulkOverwriteGuildCommands(SlashCommandCreationProperties[] commandProperties, ulong guildId, RequestOptions options = null) + => InteractionHelper.BulkOverwriteGuildCommands(this, guildId, commandProperties, options); + public Task> BatchEditGuildCommandPermissions(ulong guildId, IDictionary permissions, RequestOptions options = null) + => InteractionHelper.BatchEditGuildCommandPermissionsAsync(this, guildId, permissions, options); + + public Task AddRoleAsync(ulong guildId, ulong userId, ulong roleId) => ClientHelper.AddRoleAsync(this, guildId, userId, roleId); public Task RemoveRoleAsync(ulong guildId, ulong userId, ulong roleId) diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs index 58a4ea2c8..f0eaaf7df 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs @@ -270,6 +270,20 @@ namespace Discord.Rest return RestGuildIntegration.Create(client, guild, model); } + //Interactions + public static async Task> GetSlashCommandsAsync(IGuild guild, BaseDiscordClient client, + RequestOptions options) + { + var models = await client.ApiClient.GetGuildApplicationCommandsAsync(guild.Id, options); + return models.Select(x => RestGuildCommand.Create(client, x, guild.Id)).ToImmutableArray(); + } + public static async Task GetSlashCommandAsync(IGuild guild, ulong id, BaseDiscordClient client, + RequestOptions options) + { + var model = await client.ApiClient.GetGuildApplicationCommandAsync(guild.Id, id, options); + return RestGuildCommand.Create(client, model, guild.Id); + } + //Invites public static async Task> GetInvitesAsync(IGuild guild, BaseDiscordClient client, RequestOptions options) diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs index ea703a26a..6c561002e 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs @@ -255,7 +255,30 @@ namespace Discord.Rest public Task LeaveAsync(RequestOptions options = null) => GuildHelper.LeaveAsync(this, Discord, options); - //Bans + //Interactions + /// + /// Gets a collection of slash commands created by the current user in this guild. + /// + /// The options to be used when sending the request. + /// + /// 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); + + /// + /// Gets a slash command in the current guild. + /// + /// The unique identifier of the slash command. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a + /// slash command created by the current user. + /// + public Task GetSlashCommandAsync(ulong id, RequestOptions options = null) + => GuildHelper.GetSlashCommandAsync(this, id, Discord, options); + //Bans /// /// Gets a collection of all users banned in this guild. diff --git a/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs b/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs index a02bf9045..618dd87e7 100644 --- a/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs +++ b/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs @@ -10,20 +10,20 @@ namespace Discord.Rest { internal static class InteractionHelper { - internal static Task SendInteractionResponse(BaseDiscordClient client, IMessageChannel channel, InteractionResponse response, + public static Task SendInteractionResponse(BaseDiscordClient client, IMessageChannel channel, InteractionResponse response, ulong interactionId, string interactionToken, RequestOptions options = null) { return client.ApiClient.CreateInteractionResponse(response, interactionId, interactionToken, options); } - internal static async Task GetOriginalResponseAsync(BaseDiscordClient client, IMessageChannel channel, + public static async Task GetOriginalResponseAsync(BaseDiscordClient client, IMessageChannel channel, IDiscordInteraction interaction, RequestOptions options = null) { var model = await client.ApiClient.GetInteractionResponse(interaction.Token, options).ConfigureAwait(false); return RestInteractionMessage.Create(client, model, interaction.Token, channel); } - internal static async Task SendFollowupAsync(BaseDiscordClient client, CreateWebhookMessageParams args, + public static async Task SendFollowupAsync(BaseDiscordClient client, CreateWebhookMessageParams args, string token, IMessageChannel channel, RequestOptions options = null) { var model = await client.ApiClient.CreateInteractionFollowupMessage(args, token, options).ConfigureAwait(false); @@ -31,47 +31,128 @@ namespace Discord.Rest RestFollowupMessage entity = RestFollowupMessage.Create(client, model, token, channel); return entity; } - + // Global commands - internal static async Task CreateGlobalCommand(BaseDiscordClient client, + public static async Task CreateGlobalCommand(BaseDiscordClient client, Action func, RequestOptions options = null) { var args = new SlashCommandCreationProperties(); func(args); return await CreateGlobalCommand(client, args, options).ConfigureAwait(false); } - internal static async Task CreateGlobalCommand(BaseDiscordClient client, - SlashCommandCreationProperties args, RequestOptions options = null) + public static async Task CreateGlobalCommand(BaseDiscordClient client, + SlashCommandCreationProperties arg, RequestOptions options = null) { - if (args.Options.IsSpecified) - { - if (args.Options.Value.Count > 10) - throw new ArgumentException("Option count must be 10 or less"); - } + Preconditions.NotNullOrEmpty(arg.Name, nameof(arg.Name)); + Preconditions.NotNullOrEmpty(arg.Description, nameof(arg.Description)); - + if (arg.Options.IsSpecified) + Preconditions.AtMost(arg.Options.Value.Count, 25, nameof(arg.Options)); var model = new CreateApplicationCommandParams() { - Name = args.Name, - Description = args.Description, - Options = args.Options.IsSpecified - ? args.Options.Value.Select(x => new Discord.API.ApplicationCommandOption(x)).ToArray() + Name = arg.Name, + Description = arg.Description, + Options = arg.Options.IsSpecified + ? arg.Options.Value.Select(x => new Discord.API.ApplicationCommandOption(x)).ToArray() : Optional.Unspecified, - DefaultPermission = args.DefaultPermission.IsSpecified - ? args.DefaultPermission.Value + DefaultPermission = arg.DefaultPermission.IsSpecified + ? arg.DefaultPermission.Value : Optional.Unspecified }; var cmd = await client.ApiClient.CreateGlobalApplicationCommandAsync(model, options).ConfigureAwait(false); return RestGlobalCommand.Create(client, cmd); } - internal static async Task ModifyGlobalCommand(BaseDiscordClient client, RestGlobalCommand command, + + public static async Task> BulkOverwriteGlobalCommands(BaseDiscordClient client, + SlashCommandCreationProperties[] args, RequestOptions options = null) + { + Preconditions.NotNull(args, nameof(args)); + + List models = new List(); + + foreach (var arg in args) + { + Preconditions.NotNullOrEmpty(arg.Name, nameof(arg.Name)); + Preconditions.NotNullOrEmpty(arg.Description, nameof(arg.Description)); + + if (arg.Options.IsSpecified) + Preconditions.AtMost(arg.Options.Value.Count, 25, nameof(arg.Options)); + + var model = new CreateApplicationCommandParams() + { + Name = arg.Name, + Description = arg.Description, + Options = arg.Options.IsSpecified + ? arg.Options.Value.Select(x => new Discord.API.ApplicationCommandOption(x)).ToArray() + : Optional.Unspecified, + DefaultPermission = arg.DefaultPermission.IsSpecified + ? arg.DefaultPermission.Value + : Optional.Unspecified + }; + + models.Add(model); + } + + var apiModels = await client.ApiClient.BulkOverwriteGlobalApplicationCommands(models.ToArray(), options); + + return apiModels.Select(x => RestGlobalCommand.Create(client, x)).ToArray(); + } + + public static async Task> BulkOverwriteGuildCommands(BaseDiscordClient client, ulong guildId, + SlashCommandCreationProperties[] args, RequestOptions options = null) + { + Preconditions.NotNull(args, nameof(args)); + + List models = new List(); + + foreach (var arg in args) + { + Preconditions.NotNullOrEmpty(arg.Name, nameof(arg.Name)); + Preconditions.NotNullOrEmpty(arg.Description, nameof(arg.Description)); + + if (arg.Options.IsSpecified) + Preconditions.AtMost(arg.Options.Value.Count, 25, nameof(arg.Options)); + + var model = new CreateApplicationCommandParams() + { + Name = arg.Name, + Description = arg.Description, + Options = arg.Options.IsSpecified + ? arg.Options.Value.Select(x => new Discord.API.ApplicationCommandOption(x)).ToArray() + : Optional.Unspecified, + DefaultPermission = arg.DefaultPermission.IsSpecified + ? arg.DefaultPermission.Value + : Optional.Unspecified + }; + + models.Add(model); + } + + var apiModels = await client.ApiClient.BulkOverwriteGuildApplicationCommands(guildId, models.ToArray(), options); + + return apiModels.Select(x => RestGuildCommand.Create(client, x, guildId)).ToArray(); + } + + public static async Task ModifyGlobalCommand(BaseDiscordClient client, RestGlobalCommand command, Action func, RequestOptions options = null) { ApplicationCommandProperties args = new ApplicationCommandProperties(); func(args); + if (args.Name.IsSpecified) + { + Preconditions.AtMost(args.Name.Value.Length, 32, nameof(args.Name)); + Preconditions.AtLeast(args.Name.Value.Length, 3, nameof(args.Name)); + } + if (args.Description.IsSpecified) + { + Preconditions.AtMost(args.Description.Value.Length, 100, nameof(args.Description)); + Preconditions.AtLeast(args.Description.Value.Length, 1, nameof(args.Description)); + } + + if (args.Options.IsSpecified) { if (args.Options.Value.Count > 10) @@ -96,7 +177,7 @@ namespace Discord.Rest } - internal static async Task DeleteGlobalCommand(BaseDiscordClient client, RestGlobalCommand command, RequestOptions options = null) + public static async Task DeleteGlobalCommand(BaseDiscordClient client, RestGlobalCommand command, RequestOptions options = null) { Preconditions.NotNull(command, nameof(command)); Preconditions.NotEqual(command.Id, 0, nameof(command.Id)); @@ -105,7 +186,7 @@ namespace Discord.Rest } // Guild Commands - internal static async Task CreateGuildCommand(BaseDiscordClient client, ulong guildId, + public static async Task CreateGuildCommand(BaseDiscordClient client, ulong guildId, Action func, RequestOptions options = null) { var args = new SlashCommandCreationProperties(); @@ -113,19 +194,23 @@ namespace Discord.Rest return await CreateGuildCommand(client, guildId, args, options).ConfigureAwait(false); } - internal static async Task CreateGuildCommand(BaseDiscordClient client, ulong guildId, + public static async Task CreateGuildCommand(BaseDiscordClient client, ulong guildId, SlashCommandCreationProperties args, RequestOptions options = null) { Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name)); Preconditions.NotNullOrEmpty(args.Description, nameof(args.Description)); + Preconditions.AtMost(args.Name.Length, 32, nameof(args.Name)); + Preconditions.AtLeast(args.Name.Length, 3, nameof(args.Name)); + Preconditions.AtMost(args.Description.Length, 100, nameof(args.Description)); + Preconditions.AtLeast(args.Description.Length, 1, nameof(args.Description)); if (args.Options.IsSpecified) { if (args.Options.Value.Count > 10) throw new ArgumentException("Option count must be 10 or less"); - foreach(var item in args.Options.Value) + foreach (var item in args.Options.Value) { Preconditions.NotNullOrEmpty(item.Name, nameof(item.Name)); Preconditions.NotNullOrEmpty(item.Description, nameof(item.Description)); @@ -147,12 +232,23 @@ namespace Discord.Rest var cmd = await client.ApiClient.CreateGuildApplicationCommandAsync(model, guildId, options).ConfigureAwait(false); return RestGuildCommand.Create(client, cmd, guildId); } - internal static async Task ModifyGuildCommand(BaseDiscordClient client, RestGuildCommand command, + public static async Task ModifyGuildCommand(BaseDiscordClient client, RestGuildCommand command, Action func, RequestOptions options = null) { ApplicationCommandProperties args = new ApplicationCommandProperties(); func(args); + if (args.Name.IsSpecified) + { + Preconditions.AtMost(args.Name.Value.Length, 32, nameof(args.Name)); + Preconditions.AtLeast(args.Name.Value.Length, 3, nameof(args.Name)); + } + if (args.Description.IsSpecified) + { + Preconditions.AtMost(args.Description.Value.Length, 100, nameof(args.Description)); + Preconditions.AtLeast(args.Description.Value.Length, 1, nameof(args.Description)); + } + if (args.Options.IsSpecified) { if (args.Options.Value.Count > 10) @@ -176,15 +272,15 @@ namespace Discord.Rest return command; } - internal static async Task DeleteGuildCommand(BaseDiscordClient client, RestGuildCommand command, RequestOptions options = null) + public static async Task DeleteGuildCommand(BaseDiscordClient client, ulong guildId, IApplicationCommand command, RequestOptions options = null) { Preconditions.NotNull(command, nameof(command)); Preconditions.NotEqual(command.Id, 0, nameof(command.Id)); - await client.ApiClient.DeleteGuildApplicationCommandAsync(command.GuildId, command.Id, options).ConfigureAwait(false); + await client.ApiClient.DeleteGuildApplicationCommandAsync(guildId, command.Id, options).ConfigureAwait(false); } - internal static async Task ModifyFollowupMessage(BaseDiscordClient client, RestFollowupMessage message, Action func, + public static async Task ModifyFollowupMessage(BaseDiscordClient client, RestFollowupMessage message, Action func, RequestOptions options = null) { var args = new MessageProperties(); @@ -204,10 +300,10 @@ namespace Discord.Rest return await client.ApiClient.ModifyInteractionFollowupMessage(apiArgs, message.Id, message.Token, options).ConfigureAwait(false); } - internal static async Task DeleteFollowupMessage(BaseDiscordClient client, RestFollowupMessage message, RequestOptions options = null) + public static async Task DeleteFollowupMessage(BaseDiscordClient client, RestFollowupMessage message, RequestOptions options = null) => await client.ApiClient.DeleteInteractionFollowupMessage(message.Id, message.Token, options); - internal static async Task ModifyInteractionResponse(BaseDiscordClient client, RestInteractionMessage message, Action func, + public static async Task ModifyInteractionResponse(BaseDiscordClient client, RestInteractionMessage message, Action func, RequestOptions options = null) { var args = new MessageProperties(); @@ -227,16 +323,87 @@ namespace Discord.Rest return await client.ApiClient.ModifyInteractionFollowupMessage(apiArgs, message.Id, message.Token, options).ConfigureAwait(false); } - internal static async Task DeletedInteractionResponse(BaseDiscordClient client, RestInteractionMessage message, RequestOptions options = null) + public static async Task DeletedInteractionResponse(BaseDiscordClient client, RestInteractionMessage message, RequestOptions options = null) => await client.ApiClient.DeleteInteractionFollowupMessage(message.Id, message.Token, options); // Guild permissions - internal static async Task> GetCommandGuildPermissions(BaseDiscordClient client, - RestGuildCommand command) + public static async Task> GetGuildCommandPermissionsAsync(BaseDiscordClient client, + ulong guildId, RequestOptions options) { - // TODO - return null; + var models = await client.ApiClient.GetGuildApplicationCommandPermissions(guildId, options); + return models.Select(x => + new GuildApplicationCommandPermission(x.Id, x.ApplicationId, guildId, x.Permissions.Select( + y => new Discord.ApplicationCommandPermission(y.Id, y.Type, y.Permission)) + .ToArray()) + ).ToArray(); } + public static async Task GetGuildCommandPermissionAsync(BaseDiscordClient client, + ulong guildId, ulong commandId, RequestOptions options) + { + var model = await client.ApiClient.GetGuildApplicationCommandPermission(guildId, commandId, options); + return new GuildApplicationCommandPermission(model.Id, model.ApplicationId, guildId, model.Permissions.Select( + y => new ApplicationCommandPermission(y.Id, y.Type, y.Permission)).ToArray()); + } + + public static async Task ModifyGuildCommandPermissionsAsync(BaseDiscordClient client, ulong guildId, ulong commandId, + ApplicationCommandPermission[] args, RequestOptions options) + { + Preconditions.NotNull(args, nameof(args)); + Preconditions.AtMost(args.Length, 10, nameof(args)); + Preconditions.GreaterThan(args.Length, 0, nameof(args)); + + List models = new List(); + + foreach(var arg in args) + { + var model = new ApplicationCommandPermissions() + { + Id = arg.TargetId, + Permission = arg.Permission, + Type = arg.TargetType + }; + + models.Add(model); + } + + var apiModel = await client.ApiClient.ModifyApplicationCommandPermissions(models.ToArray(), guildId, commandId, options); + + return new GuildApplicationCommandPermission(apiModel.Id, apiModel.ApplicationId, guildId, apiModel.Permissions.Select( + x => new ApplicationCommandPermission(x.Id, x.Type, x.Permission)).ToArray()); + } + + public static async Task> BatchEditGuildCommandPermissionsAsync(BaseDiscordClient client, ulong guildId, + IDictionary args, RequestOptions options) + { + Preconditions.NotNull(args, nameof(args)); + Preconditions.NotEqual(args.Count, 0, nameof(args)); + + List models = new List(); + + foreach(var arg in args) + { + Preconditions.AtMost(arg.Value.Length, 10, nameof(args)); + + var model = new ModifyGuildApplicationCommandPermissions() + { + Id = arg.Key, + Permissions = arg.Value.Select(x => new ApplicationCommandPermissions() + { + Id = x.TargetId, + Permission = x.Permission, + Type = x.TargetType + }).ToArray() + }; + + models.Add(model); + } + + var apiModels = await client.ApiClient.BatchModifyApplicationCommandPermissions(models.ToArray(), guildId, options); + + return apiModels.Select( + x => new GuildApplicationCommandPermission(x.Id, x.ApplicationId, x.GuildId, x.Permissions.Select( + y => new ApplicationCommandPermission(y.Id, y.Type, y.Permission)).ToArray())).ToArray(); + } } } diff --git a/src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommand.cs b/src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommand.cs index 67a530d50..e1a854187 100644 --- a/src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommand.cs +++ b/src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommand.cs @@ -22,6 +22,9 @@ namespace Discord.Rest /// public string Description { get; private set; } + /// + public bool DefaultPermission { get; private set; } + /// /// The options of this command. /// @@ -58,14 +61,18 @@ namespace Discord.Rest this.ApplicationId = model.ApplicationId; this.Name = model.Name; this.Description = model.Description; + this.DefaultPermission = model.DefaultPermissions.GetValueOrDefault(true); this.Options = model.Options.IsSpecified ? model.Options.Value.Select(x => RestApplicationCommandOption.Create(x)).ToImmutableArray() : null; } + + /// + public abstract Task DeleteAsync(RequestOptions options = null); + IReadOnlyCollection IApplicationCommand.Options => Options; - public virtual Task DeleteAsync(RequestOptions options = null) => throw new NotImplementedException(); } } diff --git a/src/Discord.Net.Rest/Entities/Interactions/RestGuildCommand.cs b/src/Discord.Net.Rest/Entities/Interactions/RestGuildCommand.cs index 90e998977..33ab78dbb 100644 --- a/src/Discord.Net.Rest/Entities/Interactions/RestGuildCommand.cs +++ b/src/Discord.Net.Rest/Entities/Interactions/RestGuildCommand.cs @@ -33,7 +33,7 @@ namespace Discord.Rest /// public override async Task DeleteAsync(RequestOptions options = null) - => await InteractionHelper.DeleteGuildCommand(Discord, this).ConfigureAwait(false); + => await InteractionHelper.DeleteGuildCommand(Discord, GuildId, this).ConfigureAwait(false); /// /// Modifies this . @@ -46,7 +46,39 @@ namespace Discord.Rest public async Task ModifyAsync(Action func, RequestOptions options = null) => await InteractionHelper.ModifyGuildCommand(Discord, this, func, options).ConfigureAwait(false); - public async Task> GetCommandPermissions() - => await InteractionHelper.GetCommandGuildPermissions(Discord, this); + /// + /// Gets this commands permissions inside of the current guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a + /// object defining the permissions of the current slash command. + /// + public Task GetCommandPermission(RequestOptions options = null) + => InteractionHelper.GetGuildCommandPermissionAsync(Discord, this.GuildId, this.Id, options); + + /// + /// Modifies the current command permissions for this guild command. + /// + /// The permissions to overwrite. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous modification operation. The task result contains a + /// object containing the modified permissions. + /// + public Task ModifyCommandPermissions(ApplicationCommandPermission[] permissions, RequestOptions options = null) + => InteractionHelper.ModifyGuildCommandPermissionsAsync(Discord, this.GuildId, this.Id, permissions, options); + + /// + /// Gets the guild that this slash command resides in. + /// + /// if you want the approximate member and presence counts for the guild, otherwise . + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a + /// . + /// + public Task GetGuild(bool withCounts = false, RequestOptions options = null) + => ClientHelper.GetGuildAsync(this.Discord, this.GuildId, withCounts, options); } } diff --git a/src/Discord.Net.WebSocket/API/Gateway/ApplicationCommandCreatedUpdatedEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/ApplicationCommandCreatedUpdatedEvent.cs index ac6c73c66..190eca89d 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/ApplicationCommandCreatedUpdatedEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/ApplicationCommandCreatedUpdatedEvent.cs @@ -26,5 +26,8 @@ namespace Discord.API.Gateway [JsonProperty("options")] public Optional> Options { get; set; } + + [JsonProperty("default_permission")] + public Optional DefaultPermission { get; set; } } } diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml index c382c7e27..fb2082c2d 100644 --- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml +++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml @@ -2843,6 +2843,27 @@ voice regions the guild can access. + + + Gets a collection of slash commands created by the current user in this guild. + + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains a read-only collection of + slash commands created by the current user. + + + + + Gets a slash command in the current guild. + + The unique identifier of the slash command. + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains a + slash command created by the current user. + + Gets a collection of all invites in this guild. @@ -3243,6 +3264,9 @@ + + + A collection of 's recieved over the gateway. @@ -3256,6 +3280,9 @@ The where this application was created. + + + Represents a choice for a . diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index b4f6bd086..ef4e87305 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -723,6 +723,30 @@ namespace Discord.WebSocket public Task CreateIntegrationAsync(ulong id, string type, RequestOptions options = null) => GuildHelper.CreateIntegrationAsync(this, Discord, id, type, options); + //Interactions + /// + /// Gets a collection of slash commands created by the current user in this guild. + /// + /// The options to be used when sending the request. + /// + /// 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); + + /// + /// Gets a slash command in the current guild. + /// + /// The unique identifier of the slash command. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a + /// slash command created by the current user. + /// + public Task GetSlashCommandAsync(ulong id, RequestOptions options = null) + => GuildHelper.GetSlashCommandAsync(this, id, Discord, options); + //Invites /// /// Gets a collection of all invites in this guild. diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketApplicationCommand.cs b/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketApplicationCommand.cs index 70b3a52a2..81decb4be 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketApplicationCommand.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketApplicationCommand.cs @@ -1,3 +1,4 @@ +using Discord.Rest; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -22,6 +23,9 @@ namespace Discord.WebSocket /// public string Description { get; private set; } + /// + public bool DefaultPermission { get; private set; } + /// /// A collection of 's recieved over the gateway. /// @@ -56,13 +60,18 @@ namespace Discord.WebSocket this.Description = model.Description; this.Name = model.Name; this.GuildId = model.GuildId; + this.DefaultPermission = model.DefaultPermission.GetValueOrDefault(true); + this.Options = model.Options.IsSpecified ? model.Options.Value.Select(x => SocketApplicationCommandOption.Create(x)).ToImmutableArray() : new ImmutableArray(); } - public Task DeleteAsync(RequestOptions options = null) => throw new NotImplementedException(); + /// + public Task DeleteAsync(RequestOptions options = null) + => InteractionHelper.DeleteGuildCommand(Discord, this.GuildId, this, options); + IReadOnlyCollection IApplicationCommand.Options => Options; } } diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandData.cs b/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandData.cs index 3557aacd2..6ed77b997 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandData.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandData.cs @@ -54,9 +54,20 @@ namespace Discord.WebSocket { foreach (var channel in resolved.Channels.Value) { - SocketChannel socketChannel = channel.Value.GuildId.IsSpecified - ? SocketGuildChannel.Create(Discord.GetGuild(channel.Value.GuildId.Value), Discord.State, channel.Value) - : SocketDMChannel.Create(Discord, Discord.State, channel.Value); + SocketChannel socketChannel = guild != null + ? guild.GetChannel(channel.Value.Id) + : Discord.GetChannel(channel.Value.Id); + + if (socketChannel == null) + { + var channelModel = guild != null + ? Discord.Rest.ApiClient.GetChannelAsync(guild.Id, channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult() + : Discord.Rest.ApiClient.GetChannelAsync(channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult(); + + socketChannel = guild != null + ? SocketGuildChannel.Create(guild, Discord.State, channelModel) + : (SocketChannel)SocketChannel.CreatePrivate(Discord, Discord.State, channelModel); + } Discord.State.AddChannel(socketChannel); this.channels.Add(ulong.Parse(channel.Key), socketChannel); diff --git a/src/Discord.Net/Discord.Net.nuspec b/src/Discord.Net/Discord.Net.nuspec index 532f681ed..b8e646e04 100644 --- a/src/Discord.Net/Discord.Net.nuspec +++ b/src/Discord.Net/Discord.Net.nuspec @@ -2,7 +2,7 @@ Discord.Net.Labs - 2.4.2$suffix$ + 2.4.3$suffix$ Discord.Net Labs Discord.Net Contributors quinchs @@ -15,22 +15,22 @@ - - + + - - - + + + - - + +