From 62c3885fb1c7976c91e89b499a31bd54d61a0869 Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Tue, 3 Aug 2021 20:28:21 -0300 Subject: [PATCH 01/23] Update README.md --- README.md | 103 +++++++++++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 41c902b0d..000d326ab 100644 --- a/README.md +++ b/README.md @@ -15,16 +15,16 @@ Setting up labs in your project is really simple, here's how to do it: ## Branches ### Dev -The main branch we pull off of to introduce new features into, the dev branch is the same as Discord.Nets dev branch +This branch is kept up to date with dnets dev branch. we pull of it to ensure that labs will work with pre existing dnet code. -### Interactions -This branch is for anything todo with Discord Interactions, such as [Slash commands](https://discord.com/developers/docs/interactions/slash-commands) and [Message Components](https://discord.com/developers/docs/interactions/message-components). This branch is stable enough to use but does not contain all the features of interactions. +### release/2.x +This branch is what will be pushed to nuget, sometimes its not up to date as we wait for other features to be finished. -### SlashCommandService -This branch is on pause and does not work currently, Once everything is stable with the Interaction branch we will continue working on a slash command service for it. +### old/SlashCommandService +This branch is on pause and does not work currently, There is a pull request open to implement a working version of a slash command service. It can be found [here](https://github.com/Discord-Net-Labs/Discord.Net-Labs/pull/52) -### web/SlashCommandService -webmilio's spin on the SlashCommandService branch, again the state of this is unknown. +### feature/xyz +These branches are features for new things, you are more than welcome to clone them and give feedback in the discord server or issues tab. ## Listening for interactions ```cs @@ -32,52 +32,65 @@ webmilio's spin on the SlashCommandService branch, again the state of this is un client.InteractionCreated += Client_InteractionCreated; ... -private async Task Client_InteractionCreated(SocketInteraction arg) +private async Task Client_InteractionCreated(SocketInteraction interaction) { - switch (arg.Type) // We want to check the type of this interaction + // Checking the type of this interaction + switch (interaction) { - //Slash commands - case InteractionType.ApplicationCommand: - await MySlashCommandHandler(arg); + // Slash commands + case SocketSlashCommand commandInteraction: + await MySlashCommandHandler(commandInteraction); break; - //Button clicks/selection dropdowns - case InteractionType.MessageComponent: - await MyMessageComponentHandler(arg); + + // Button clicks/selection dropdowns + case SocketMessageComponent componentInteraction: + await MyMessageComponentHandler(componentInteraction); break; - //Unused - case InteractionType.Ping: - break; - //Unknown/Unsupported + + // Unused or Unknown/Unsupported default: - Console.WriteLine("Unsupported interaction type: " + arg.Type); break; } } ``` -### Handling button clicks and selection dropdowns +### Simple handling slash commands ```cs -private async Task MyMessageComponentHandler(SocketInteraction arg) +private async Task MySlashCommandHandler(SocketSlashCommand interaction) +{ + // Checking command name + if (interaction.Data.Name == "ping") + { + // Respond to interaction with message. + // You can also use "ephemeral" so that only the original user of the interaction sees the message + await interaction.RespondAsync($"Pong!", ephemeral: true); + + // Also you can followup with a additional messages, which also can be "ephemeral" + await interaction.FollowupAsync($"PongPong!", ephemeral: true); + } +} +``` + +### Simple handling button clicks and selection dropdowns +```cs +private async Task MyMessageComponentHandler(SocketMessageComponent interaction) { - // Parse the arg - var parsedArg = (SocketMessageComponent) arg; // Get the custom ID - var customId = parsedArg.Data.CustomId; + var customId = interaction.Data.CustomId; // Get the user - var user = (SocketGuildUser) arg.User; + var user = (SocketGuildUser) interaction.User; // Get the guild var guild = user.Guild; - // Respond with the update message response type. This edits the original message if you have set AlwaysAcknowledgeInteractions to false. - // You can also use "ephemeral" so that only the original user of the interaction sees the message - await parsedArg.RespondAsync($"Clicked {parsedArg.Data.CustomId}!", type: InteractionResponseType.UpdateMessage, ephemeral: true); + // Respond with the update message. This edits the message which this component resides. + await interaction.UpdateAsync(msgProps => msgProps.Content = $"Clicked {interaction.Data.CustomId}!"); - // You can also followup with a second message - await parsedArg.FollowupAsync($"Clicked {parsedArg.Data.CustomId}!", type: InteractionResponseType.ChannelMessageWithSource, ephemeral: true); + // Also you can followup with a additional messages + await interaction.FollowupAsync($"Clicked {interaction.Data.CustomId}!", ephemeral: true); - //If you are using selection dropdowns, you can get the selected label and values using these: - var selectedLabel = ((SelectMenu) parsedArg.Message.Components.First().Components.First()).Options.FirstOrDefault(x => x.Value == parsedArg.Data.Values.FirstOrDefault())?.Label; - var selectedValue = parsedArg.Data.Values.First(); + // If you are using selection dropdowns, you can get the selected label and values using these + var selectedLabel = ((SelectMenu) interaction.Message.Components.First().Components.First()).Options.FirstOrDefault(x => x.Value == interaction.Data.Values.FirstOrDefault())?.Label; + var selectedValue = interaction.Data.Values.First(); } ``` @@ -97,22 +110,18 @@ var builder = new ComponentBuilder() .WithSelectMenu(new SelectMenuBuilder() .WithCustomId("id_2") .WithPlaceholder("This is a placeholder") - .WithOptions(new List() - { - new SelectMenuOptionBuilder() - .WithLabel("Option A") - .WithEmote(Emote.Parse("<:evanpog:810017136814194698>")) - .WithDescription("Evan pog champ") - .WithValue("value1"), - new SelectMenuOptionBuilder() - .WithLabel("Option B") - .WithDescription("Option B is poggers") - .WithValue("value2") - })); + .AddOption( + label: "Option", + value: "value1", + description: "Evan pog champ", + emote: Emote.Parse("<:evanpog:810017136814194698>") + ) + .AddOption("Option B", "value2", "Option B is poggers"); + await Context.Channel.SendMessageAsync("Test selection!", component: builder.Build()); ``` > Note: You can only have 5 buttons per row and 5 rows per message. If a row contains a selection dropdown it cannot contain any buttons. ## Slash commands -Slash command example how to's can be found [here](https://github.com/Discord-Net-Labs/Discord.Net-Labs/tree/Interactions/docs/guides/slash-commands). If you want to read some code using slash commands, you can do that [here](https://github.com/quinchs/SwissbotCore/blob/master/SwissbotCore/Handlers/AutoMod/Censor.cs) +Slash command example how to's can be found [here](https://github.com/Discord-Net-Labs/Discord.Net-Labs/tree/Interactions/docs/guides/slash-commands). From 6e9d4c63900c6f8e57f1ec49cf5334468786f4f8 Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Tue, 3 Aug 2021 20:43:16 -0300 Subject: [PATCH 02/23] Update README.md --- README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 000d326ab..f0d40c20c 100644 --- a/README.md +++ b/README.md @@ -108,15 +108,16 @@ Theres a new field in all `SendMessageAsync` functions that takes in a `MessageC ```cs var builder = new ComponentBuilder() .WithSelectMenu(new SelectMenuBuilder() - .WithCustomId("id_2") - .WithPlaceholder("This is a placeholder") - .AddOption( - label: "Option", - value: "value1", - description: "Evan pog champ", - emote: Emote.Parse("<:evanpog:810017136814194698>") - ) - .AddOption("Option B", "value2", "Option B is poggers"); + .WithCustomId("id_2") + .WithPlaceholder("This is a placeholder") + .AddOption( + label: "Option", + value: "value1", + description: "Evan pog champ", + emote: Emote.Parse("<:evanpog:810017136814194698>") + ) + .AddOption("Option B", "value2", "Option B is poggers") + ); await Context.Channel.SendMessageAsync("Test selection!", component: builder.Build()); ``` From 7c3feadd5f6c4b3ba4d498b523c1bba9593c7044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Fri, 6 Aug 2021 17:56:43 +0200 Subject: [PATCH 03/23] Fix SocketSlashCommandDataOption to use long for Number instead of int (#89) --- .../Slash Commands/SocketSlashCommandDataOption.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandDataOption.cs b/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandDataOption.cs index f33008cf3..f9c12257e 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandDataOption.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandDataOption.cs @@ -86,9 +86,9 @@ namespace Discord.WebSocket break; case ApplicationCommandOptionType.Integer: { - if (model.Value.Value is int val) + if (model.Value.Value is long val) this.Value = val; - else if (int.TryParse(model.Value.Value.ToString(), out int res)) + else if (long.TryParse(model.Value.Value.ToString(), out long res)) this.Value = res; } break; @@ -109,7 +109,7 @@ namespace Discord.WebSocket } break; } - + } this.Options = model.Options.IsSpecified From 860fd824655bbeee69eca35894a9495fdfbf3860 Mon Sep 17 00:00:00 2001 From: drobbins329 Date: Fri, 6 Aug 2021 11:58:37 -0400 Subject: [PATCH 04/23] Application webhooks (#86) * Added webhook components for hooks having an application ID. --- src/Discord.Net.Core/Discord.Net.Core.xml | 5 +++++ src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs | 7 ++++++- src/Discord.Net.Rest/API/Common/Webhook.cs | 2 ++ .../API/Rest/ModifyWebhookMessageParams.cs | 2 ++ src/Discord.Net.Rest/Discord.Net.Rest.xml | 3 +++ src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs | 4 ++++ src/Discord.Net.Rest/Extensions/EntityExtensions.cs | 1 + src/Discord.Net.Webhook/Discord.Net.Webhook.xml | 7 ++++++- src/Discord.Net.Webhook/DiscordWebhookClient.cs | 4 ++-- .../Entities/Messages/WebhookMessageProperties.cs | 4 ++++ .../Entities/Webhooks/RestInternalWebhook.cs | 3 +++ src/Discord.Net.Webhook/WebhookClientHelper.cs | 7 +++++-- 12 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml index ca9e9696f..13bbc8eb5 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.xml +++ b/src/Discord.Net.Core/Discord.Net.Core.xml @@ -10089,6 +10089,11 @@ Gets the user that created this webhook. + + + Gets the ID of the application owning this webhook. + + Modifies this webhook. diff --git a/src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs b/src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs index b2d017316..d5bc70d71 100644 --- a/src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs +++ b/src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading.Tasks; namespace Discord @@ -49,6 +49,11 @@ namespace Discord /// IUser Creator { get; } + /// + /// Gets the ID of the application owning this webhook. + /// + ulong? ApplicationId { get; } + /// /// Modifies this webhook. /// diff --git a/src/Discord.Net.Rest/API/Common/Webhook.cs b/src/Discord.Net.Rest/API/Common/Webhook.cs index cbd5fdad5..ff1dca9bd 100644 --- a/src/Discord.Net.Rest/API/Common/Webhook.cs +++ b/src/Discord.Net.Rest/API/Common/Webhook.cs @@ -21,5 +21,7 @@ namespace Discord.API [JsonProperty("user")] public Optional Creator { get; set; } + [JsonProperty("application_id")] + public Optional ApplicationId { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs index ba8fcbb4e..8298ff19c 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs @@ -12,5 +12,7 @@ namespace Discord.API.Rest public Optional Embeds { get; set; } [JsonProperty("allowed_mentions")] public Optional AllowedMentions { get; set; } + [JsonProperty("components")] + public Optional Components { get; set; } } } diff --git a/src/Discord.Net.Rest/Discord.Net.Rest.xml b/src/Discord.Net.Rest/Discord.Net.Rest.xml index c8865f786..e92b92725 100644 --- a/src/Discord.Net.Rest/Discord.Net.Rest.xml +++ b/src/Discord.Net.Rest/Discord.Net.Rest.xml @@ -4766,6 +4766,9 @@ + + + diff --git a/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs b/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs index 9baddf003..0d24f08df 100644 --- a/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs +++ b/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs @@ -24,6 +24,8 @@ namespace Discord.Rest public ulong? GuildId { get; private set; } /// public IUser Creator { get; private set; } + /// + public ulong? ApplicationId { get; private set; } /// public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); @@ -66,6 +68,8 @@ namespace Discord.Rest GuildId = model.GuildId.Value; if (model.Name.IsSpecified) Name = model.Name.Value; + if (model.ApplicationId.IsSpecified) + ApplicationId = model.ApplicationId.Value; } /// diff --git a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs index f8676c783..0c2e0f8c2 100644 --- a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs +++ b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs @@ -68,6 +68,7 @@ namespace Discord.Rest model.Video = entity.Video.Value.ToModel(); return model; } + public static API.AllowedMentions ToModel(this AllowedMentions entity) { return new API.AllowedMentions() diff --git a/src/Discord.Net.Webhook/Discord.Net.Webhook.xml b/src/Discord.Net.Webhook/Discord.Net.Webhook.xml index f629c2c29..d1bafb9a3 100644 --- a/src/Discord.Net.Webhook/Discord.Net.Webhook.xml +++ b/src/Discord.Net.Webhook/Discord.Net.Webhook.xml @@ -31,7 +31,7 @@ Thrown if the is an invalid format. Thrown if the is null or whitespace. - + Sends a message to the channel for this webhook. Returns the ID of the created message. @@ -99,6 +99,11 @@ Gets or sets the allowed mentions of the message. + + + Gets or sets the components that the message should display. + + Could not find a webhook with the supplied credentials. diff --git a/src/Discord.Net.Webhook/DiscordWebhookClient.cs b/src/Discord.Net.Webhook/DiscordWebhookClient.cs index 91d077411..d4affb08b 100644 --- a/src/Discord.Net.Webhook/DiscordWebhookClient.cs +++ b/src/Discord.Net.Webhook/DiscordWebhookClient.cs @@ -88,8 +88,8 @@ namespace Discord.Webhook /// Sends a message to the channel for this webhook. /// Returns the ID of the created message. public Task SendMessageAsync(string text = null, bool isTTS = false, IEnumerable embeds = null, - string username = null, string avatarUrl = null, RequestOptions options = null, AllowedMentions allowedMentions = null) - => WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, allowedMentions, options); + string username = null, string avatarUrl = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent component = null) + => WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, component); /// /// Modifies a message posted using this webhook. diff --git a/src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs b/src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs index dec7b6e3b..ca2ff10a0 100644 --- a/src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs +++ b/src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs @@ -22,5 +22,9 @@ namespace Discord.Webhook /// Gets or sets the allowed mentions of the message. /// public Optional AllowedMentions { get; set; } + /// + /// Gets or sets the components that the message should display. + /// + public Optional Components { get; set; } } } diff --git a/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs b/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs index bbb160fcd..210d8eda0 100644 --- a/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs +++ b/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs @@ -17,6 +17,7 @@ namespace Discord.Webhook public string Name { get; private set; } public string AvatarId { get; private set; } public ulong? GuildId { get; private set; } + public ulong? ApplicationId { get; private set; } public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); @@ -44,6 +45,8 @@ namespace Discord.Webhook GuildId = model.GuildId.Value; if (model.Name.IsSpecified) Name = model.Name.Value; + if (model.ApplicationId.IsSpecified) + ApplicationId = model.ApplicationId.Value; } public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) diff --git a/src/Discord.Net.Webhook/WebhookClientHelper.cs b/src/Discord.Net.Webhook/WebhookClientHelper.cs index 528848f7f..6e3651323 100644 --- a/src/Discord.Net.Webhook/WebhookClientHelper.cs +++ b/src/Discord.Net.Webhook/WebhookClientHelper.cs @@ -21,7 +21,7 @@ namespace Discord.Webhook return RestInternalWebhook.Create(client, model); } public static async Task SendMessageAsync(DiscordWebhookClient client, - string text, bool isTTS, IEnumerable embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options) + string text, bool isTTS, IEnumerable embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options, MessageComponent component) { var args = new CreateWebhookMessageParams { @@ -37,6 +37,8 @@ namespace Discord.Webhook args.AvatarUrl = avatarUrl; if (allowedMentions != null) args.AllowedMentions = allowedMentions.ToModel(); + if (component != null) + args.Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray(); var model = await client.ApiClient.CreateWebhookMessageAsync(client.Webhook.Id, args, options: options).ConfigureAwait(false); return model.Id; @@ -83,7 +85,8 @@ namespace Discord.Webhook : Optional.Create(), AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() - : Optional.Create() + : Optional.Create(), + Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional.Unspecified, }; await client.ApiClient.ModifyWebhookMessageAsync(client.Webhook.Id, messageId, apiArgs, options) From 75892660d0412e2f875342246d6d4e4a69fb1fee Mon Sep 17 00:00:00 2001 From: quin lynch Date: Fri, 6 Aug 2021 13:09:34 -0300 Subject: [PATCH 05/23] resolved #88 --- .../API/Common/InteractionCallbackData.cs | 2 +- .../API/Rest/CreateWebhookMessageParams.cs | 2 +- .../Discord.Net.WebSocket.xml | 23 ++++++------------- .../SocketMessageComponent.cs | 18 ++++++--------- .../Slash Commands/SocketSlashCommand.cs | 14 ++++------- .../Entities/Interaction/SocketInteraction.cs | 6 +++-- 6 files changed, 25 insertions(+), 40 deletions(-) diff --git a/src/Discord.Net.Rest/API/Common/InteractionCallbackData.cs b/src/Discord.Net.Rest/API/Common/InteractionCallbackData.cs index f03cb8870..ba233cc6b 100644 --- a/src/Discord.Net.Rest/API/Common/InteractionCallbackData.cs +++ b/src/Discord.Net.Rest/API/Common/InteractionCallbackData.cs @@ -18,7 +18,7 @@ namespace Discord.API // New flags prop. this make the response "ephemeral". see https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionapplicationcommandcallbackdata [JsonProperty("flags")] - public Optional Flags { get; set; } + public Optional Flags { get; set; } [JsonProperty("components")] public Optional Components { get; set; } diff --git a/src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs b/src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs index bd4cc1a6c..1806d487c 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs @@ -28,7 +28,7 @@ namespace Discord.API.Rest public Optional AllowedMentions { get; set; } [JsonProperty("flags")] - public Optional Flags { get; set; } + public Optional Flags { get; set; } [JsonProperty("components")] public Optional Components { get; set; } diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml index d22c00429..576fcc5f0 100644 --- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml +++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml @@ -3628,14 +3628,8 @@ - - - Acknowledges this interaction with the . - - The request options for this async request. - - A task that represents the asynchronous operation of acknowledging the interaction. - + + @@ -3747,13 +3741,8 @@ - - - Acknowledges this interaction with the . - - - A task that represents the asynchronous operation of acknowledging the interaction. - + + @@ -3888,10 +3877,12 @@ A task that represents the asynchronous operation of acknowledging the interaction. - + Acknowledges this interaction. + to send this message ephemerally, otherwise . + The request options for this async request. A task that represents the asynchronous operation of acknowledging the interaction. diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs b/src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs index 921f81de4..a31b30f5f 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs @@ -123,7 +123,7 @@ namespace Discord.WebSocket }; if (ephemeral) - response.Data.Value.Flags = 64; + response.Data.Value.Flags = MessageFlags.Ephemeral; await InteractionHelper.SendInteractionResponse(this.Discord, response, this.Id, Token, options); } @@ -180,7 +180,7 @@ namespace Discord.WebSocket Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional.Unspecified, - Flags = args.Flags.IsSpecified ? (int?)args.Flags.Value ?? Optional.Unspecified : Optional.Unspecified + Flags = args.Flags.IsSpecified ? args.Flags.Value ?? Optional.Unspecified : Optional.Unspecified } }; @@ -217,23 +217,19 @@ namespace Discord.WebSocket }; if (ephemeral) - args.Flags = 64; + args.Flags = MessageFlags.Ephemeral; return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options); } - /// - /// Acknowledges this interaction with the . - /// - /// The request options for this async request. - /// - /// A task that represents the asynchronous operation of acknowledging the interaction. - /// - public override Task DeferAsync(RequestOptions options = null) + /// + public override Task DeferAsync(bool ephemeral = false, RequestOptions options = null) { var response = new API.InteractionResponse() { Type = InteractionResponseType.DeferredUpdateMessage, + Data = ephemeral ? new API.InteractionCallbackData() { Flags = MessageFlags.Ephemeral } : Optional.Unspecified + }; return Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, this.Token, options); diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommand.cs b/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommand.cs index 245274613..bff5292c5 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommand.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommand.cs @@ -106,7 +106,7 @@ namespace Discord.WebSocket }; if (ephemeral) - response.Data.Value.Flags = 64; + response.Data.Value.Flags = MessageFlags.Ephemeral; await InteractionHelper.SendInteractionResponse(this.Discord, response, this.Id, Token, options); } @@ -141,22 +141,18 @@ namespace Discord.WebSocket }; if (ephemeral) - args.Flags = 64; + args.Flags = MessageFlags.Ephemeral; return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options); } - /// - /// Acknowledges this interaction with the . - /// - /// - /// A task that represents the asynchronous operation of acknowledging the interaction. - /// - public override Task DeferAsync(RequestOptions options = null) + /// + public override Task DeferAsync(bool ephemeral = false, RequestOptions options = null) { var response = new API.InteractionResponse { Type = InteractionResponseType.DeferredChannelMessageWithSource, + Data = ephemeral ? new API.InteractionCallbackData() { Flags = MessageFlags.Ephemeral } : Optional.Unspecified }; return Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, this.Token, options); diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs index 4b2e3baec..11145fa2b 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs @@ -156,15 +156,17 @@ namespace Discord.WebSocket /// A task that represents the asynchronous operation of acknowledging the interaction. /// [Obsolete("This method deprecated, please use DeferAsync instead")] - public Task AcknowledgeAsync(RequestOptions options = null) => DeferAsync(options); + public Task AcknowledgeAsync(RequestOptions options = null) => DeferAsync(options: options); /// /// Acknowledges this interaction. /// + /// to send this message ephemerally, otherwise . + /// The request options for this async request. /// /// A task that represents the asynchronous operation of acknowledging the interaction. /// - public abstract Task DeferAsync(RequestOptions options = null); + public abstract Task DeferAsync(bool ephemeral = false, RequestOptions options = null); private bool CheckToken() { From afd9600af2ed4846d1c04b54a5b7eec257940086 Mon Sep 17 00:00:00 2001 From: quin lynch Date: Fri, 6 Aug 2021 13:21:23 -0300 Subject: [PATCH 06/23] resolved #85 --- .../SocketMessageComponent.cs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs b/src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs index a31b30f5f..7e21f6043 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs @@ -213,7 +213,7 @@ namespace Discord.WebSocket AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, IsTTS = isTTS, Embeds = embeds?.Select(x => x.ToModel()).ToArray() ?? Optional.Unspecified, - Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified, }; if (ephemeral) @@ -222,6 +222,26 @@ namespace Discord.WebSocket return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options); } + /// + /// Defers an interaction and responds with type 5 () + /// + /// to send this message ephemerally, otherwise . + /// The request options for this async request. + /// + /// A task that represents the asynchronous operation of acknowledging the interaction. + /// + public Task DeferLoadingAsync(bool ephemeral = false, RequestOptions options = null) + { + var response = new API.InteractionResponse() + { + Type = InteractionResponseType.DeferredChannelMessageWithSource, + Data = ephemeral ? new API.InteractionCallbackData() { Flags = MessageFlags.Ephemeral } : Optional.Unspecified + + }; + + return Discord.Rest.ApiClient.CreateInteractionResponse(response, this.Id, this.Token, options); + } + /// public override Task DeferAsync(bool ephemeral = false, RequestOptions options = null) { From 26c65280ef7e2d6265725da877fb09c1a66bde80 Mon Sep 17 00:00:00 2001 From: quin lynch Date: Fri, 6 Aug 2021 13:28:36 -0300 Subject: [PATCH 07/23] Update device for gateway --- src/Discord.Net.WebSocket/DiscordSocketApiClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs index 9221a3faa..a862b5778 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs @@ -237,7 +237,7 @@ namespace Discord.API options = RequestOptions.CreateOrClone(options); var props = new Dictionary { - ["$device"] = "Discord.Net" + ["$device"] = "Discord.Net Labs" }; var msg = new IdentifyParams() { From 505c39a3f096e17ef7f87be148c7942d29933b5f Mon Sep 17 00:00:00 2001 From: d4n3436 Date: Fri, 6 Aug 2021 19:46:33 -0500 Subject: [PATCH 08/23] Fix MessageProperties.Embed being ignored in some methods that modifies a message (#92) --- src/Discord.Net.Core/Discord.Net.Core.xml | 2 +- .../Entities/Messages/MessageProperties.cs | 2 +- .../Interactions/InteractionHelper.cs | 49 +++++++++++++++++-- .../Entities/Messages/MessageHelper.cs | 45 +++++++++++------ .../SocketMessageComponent.cs | 33 ++++++++++--- 5 files changed, 104 insertions(+), 27 deletions(-) diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml index 059d9d16b..0510de74a 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.xml +++ b/src/Discord.Net.Core/Discord.Net.Core.xml @@ -7602,7 +7602,7 @@ Gets or sets a single embed for this message. - This property will be added to the array, in the future please use the array rather then this property. + This property will be added to the array, in the future please use the array rather than this property. diff --git a/src/Discord.Net.Core/Entities/Messages/MessageProperties.cs b/src/Discord.Net.Core/Entities/Messages/MessageProperties.cs index 19cfacebe..abd09d856 100644 --- a/src/Discord.Net.Core/Entities/Messages/MessageProperties.cs +++ b/src/Discord.Net.Core/Entities/Messages/MessageProperties.cs @@ -22,7 +22,7 @@ namespace Discord /// Gets or sets a single embed for this message. /// /// - /// This property will be added to the array, in the future please use the array rather then this property. + /// This property will be added to the array, in the future please use the array rather than this property. /// public Optional Embed { get; set; } diff --git a/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs b/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs index e4df0d75e..7ed48a04d 100644 --- a/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs +++ b/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs @@ -296,15 +296,33 @@ namespace Discord.Rest var args = new MessageProperties(); func(args); + var embed = args.Embed; + var embeds = args.Embeds; + bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(message.Content); - bool hasEmbed = args.Embeds.IsSpecified ? args.Embeds.Value != null : message.Embeds.Any(); - if (!hasText && !hasEmbed) + bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0) || message.Embeds.Any(); + + if (!hasText && !hasEmbeds) Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); + var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List() : null; + + if (embed.IsSpecified && embed.Value != null) + { + apiEmbeds.Add(embed.Value.ToModel()); + } + + if (embeds.IsSpecified && embeds.Value != null) + { + apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); + } + + Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); + var apiArgs = new API.Rest.ModifyInteractionResponseParams { Content = args.Content, - Embeds = args.Embeds.IsSpecified ? args.Embeds.Value.Select(x => x.ToModel()).ToArray() : Optional.Create(), + Embeds = apiEmbeds?.ToArray() ?? Optional.Unspecified, AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional.Unspecified, Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional.Unspecified, }; @@ -321,10 +339,33 @@ namespace Discord.Rest var args = new MessageProperties(); func(args); + var embed = args.Embed; + var embeds = args.Embeds; + + bool hasText = !string.IsNullOrEmpty(args.Content.GetValueOrDefault()); + bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0); + + if (!hasText && !hasEmbeds) + Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); + + var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List() : null; + + if (embed.IsSpecified && embed.Value != null) + { + apiEmbeds.Add(embed.Value.ToModel()); + } + + if (embeds.IsSpecified && embeds.Value != null) + { + apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); + } + + Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); + var apiArgs = new ModifyInteractionResponseParams { Content = args.Content, - Embeds = args.Embeds.IsSpecified ? args.Embeds.Value?.Select(x => x.ToModel()).ToArray() : Optional.Unspecified, + Embeds = apiEmbeds?.ToArray() ?? Optional.Unspecified, AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value?.ToModel() : Optional.Unspecified, Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional.Unspecified, Flags = args.Flags diff --git a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs index 83ad2777e..9546025b0 100644 --- a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs +++ b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs @@ -1,3 +1,4 @@ +using Discord.API; using Discord.API.Rest; using System; using System.Collections.Generic; @@ -33,9 +34,13 @@ namespace Discord.Rest if (msg.Author.Id != client.CurrentUser.Id && (args.Content.IsSpecified || args.Embeds.IsSpecified || args.AllowedMentions.IsSpecified)) throw new InvalidOperationException("Only the author of a message may modify the message content, embed, or allowed mentions."); + var embed = args.Embed; + var embeds = args.Embeds; + bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(msg.Content); - bool hasEmbed = args.Embeds.IsSpecified ? args.Embeds.Value != null : msg.Embeds.Any(); - if (!hasText && !hasEmbed) + bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0) || msg.Embeds.Any(); + + if (!hasText && !hasEmbeds) Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); if (args.AllowedMentions.IsSpecified) @@ -61,22 +66,24 @@ namespace Discord.Rest } } - var embeds = new List(); + var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List() : null; - if (args.Embed.IsSpecified) + if (embed.IsSpecified && embed.Value != null) { - embeds.Add(args.Embed.Value.ToModel()); + apiEmbeds.Add(embed.Value.ToModel()); } - if (args.Embeds.IsSpecified) + if (embeds.IsSpecified && embeds.Value != null) { - embeds.AddRange(args.Embeds.Value.Select(x => x.ToModel())); + apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); } + Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); + var apiArgs = new ModifyMessageParams { Content = args.Content, - Embeds = embeds.ToArray(), + Embeds = apiEmbeds?.ToArray() ?? Optional.Unspecified, Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional.Unspecified, Flags = args.Flags, AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional.Unspecified, @@ -90,7 +97,13 @@ namespace Discord.Rest var args = new MessageProperties(); func(args); - if (args.Content.IsSpecified && string.IsNullOrEmpty(args.Content.Value) && args.Embeds.IsSpecified && args.Embeds.Value == null) + var embed = args.Embed; + var embeds = args.Embeds; + + bool hasText = args.Content.IsSpecified && string.IsNullOrEmpty(args.Content.Value); + bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0); + + if (!hasText && !hasEmbeds) Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); if (args.AllowedMentions.IsSpecified) @@ -117,22 +130,24 @@ namespace Discord.Rest } } - var embeds = new List(); + var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List() : null; - if (args.Embed.IsSpecified) + if (embed.IsSpecified && embed.Value != null) { - embeds.Add(args.Embed.Value.ToModel()); + apiEmbeds.Add(embed.Value.ToModel()); } - if (args.Embeds.IsSpecified) + if (embeds.IsSpecified && embeds.Value != null) { - embeds.AddRange(args.Embeds.Value.Select(x => x.ToModel())); + apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); } + Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); + var apiArgs = new API.Rest.ModifyMessageParams { Content = args.Content, - Embeds = embeds.ToArray(), + Embeds = apiEmbeds?.ToArray() ?? Optional.Unspecified, Flags = args.Flags.IsSpecified ? args.Flags.Value : Optional.Create(), AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional.Create(), Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional.Unspecified, diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs b/src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs index 7e21f6043..cc91b098f 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs @@ -4,12 +4,13 @@ using System.Threading.Tasks; using Model = Discord.API.Interaction; using DataModel = Discord.API.MessageComponentInteractionData; using Discord.Rest; +using System.Collections.Generic; namespace Discord.WebSocket { - /// - /// Represents a Websocket-based interaction type for Message Components. - /// +/// +/// Represents a Websocket-based interaction type for Message Components. +/// public class SocketMessageComponent : SocketInteraction { /// @@ -149,8 +150,28 @@ namespace Discord.WebSocket Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions), "A max of 100 user Ids are allowed."); } - if (args.Embeds.IsSpecified) - Preconditions.AtMost(args.Embeds.Value?.Length ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); + var embed = args.Embed; + var embeds = args.Embeds; + + bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(Message.Content); + bool hasEmbeds = (embed.IsSpecified && embed.Value != null) || (embeds.IsSpecified && embeds.Value?.Length > 0) || Message.Embeds.Any(); + + if (!hasText && !hasEmbeds) + Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); + + var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List() : null; + + if (embed.IsSpecified && embed.Value != null) + { + apiEmbeds.Add(embed.Value.ToModel()); + } + + if (embeds.IsSpecified && embeds.Value != null) + { + apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); + } + + Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); // check that user flag and user Id list are exclusive, same with role flag and role Id list if (args.AllowedMentions.IsSpecified && args.AllowedMentions.Value != null && args.AllowedMentions.Value.AllowedTypes.HasValue) @@ -176,7 +197,7 @@ namespace Discord.WebSocket { Content = args.Content, AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value?.ToModel() : Optional.Unspecified, - Embeds = args.Embeds.IsSpecified ? args.Embeds.Value?.Select(x => x.ToModel()).ToArray() : Optional.Unspecified, + Embeds = apiEmbeds?.ToArray() ?? Optional.Unspecified, Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional.Unspecified, From ea75a6df2c251b7ca34d5b3d8dfa9d71950f00d3 Mon Sep 17 00:00:00 2001 From: MrCakeSlayer <13650699+MrCakeSlayer@users.noreply.github.com> Date: Fri, 6 Aug 2021 20:46:41 -0400 Subject: [PATCH 09/23] Update label/description lengths for selects (ref: https://github.com/discord/discord-api-docs/pull/3598/files) (#91) https://github.com/discord/discord-api-docs/pull/3598/files --- .../Message Components/ComponentBuilder.cs | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs b/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs index bb2f80a81..8d4a710ea 100644 --- a/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs +++ b/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs @@ -13,7 +13,7 @@ namespace Discord /// /// The max length of a . /// - public const int MaxLabelLength = 80; + public const int MaxButtonLabelLength = 80; /// /// The max length of a . @@ -310,14 +310,14 @@ namespace Discord /// /// Gets or sets the label of the current button. /// - /// length exceeds . + /// length exceeds . public string Label { get => _label; set { - if (value != null && value.Length > ComponentBuilder.MaxLabelLength) - throw new ArgumentException(message: $"Button label must be {ComponentBuilder.MaxLabelLength} characters or less!", paramName: nameof(Label)); + if (value != null && value.Length > ComponentBuilder.MaxButtonLabelLength) + throw new ArgumentException(message: $"Button label must be {ComponentBuilder.MaxButtonLabelLength} characters or less!", paramName: nameof(Label)); _label = value; } @@ -834,20 +834,25 @@ namespace Discord /// /// The maximum length of a . /// - public const int MaxDescriptionLength = 50; + public const int MaxDescriptionLength = 100; + + /// + /// The maximum length of a . + /// + public const int MaxSelectLabelLength = 100; /// /// Gets or sets the label of the current select menu. /// - /// length exceeds + /// length exceeds public string Label { get => _label; set { if (value != null) - if (value.Length > ComponentBuilder.MaxLabelLength) - throw new ArgumentException(message: $"Button label must be {ComponentBuilder.MaxLabelLength} characters or less!", paramName: nameof(Label)); + if (value.Length > MaxSelectLabelLength) + throw new ArgumentException(message: $"Button label must be {MaxSelectLabelLength} characters or less!", paramName: nameof(Label)); _label = value; } From e6efead6a1c60e9cbc31f4ac5bd3dfb2c9b98ddd Mon Sep 17 00:00:00 2001 From: d4n3436 Date: Fri, 6 Aug 2021 19:46:58 -0500 Subject: [PATCH 10/23] Fix tests (#90) --- test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs b/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs index 137dc5575..bb841fd1b 100644 --- a/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs +++ b/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs @@ -91,7 +91,7 @@ namespace Discord AssertFlag(() => new GuildPermissions(manageNicknames: true), GuildPermission.ManageNicknames); AssertFlag(() => new GuildPermissions(manageRoles: true), GuildPermission.ManageRoles); AssertFlag(() => new GuildPermissions(manageWebhooks: true), GuildPermission.ManageWebhooks); - AssertFlag(() => new GuildPermissions(manageEmojis: true), GuildPermission.ManageEmojis); + AssertFlag(() => new GuildPermissions(manageEmojis: true), GuildPermission.ManageEmojisAndStickers); } /// @@ -161,7 +161,7 @@ namespace Discord AssertUtil(GuildPermission.ManageNicknames, x => x.ManageNicknames, (p, enable) => p.Modify(manageNicknames: enable)); AssertUtil(GuildPermission.ManageRoles, x => x.ManageRoles, (p, enable) => p.Modify(manageRoles: enable)); AssertUtil(GuildPermission.ManageWebhooks, x => x.ManageWebhooks, (p, enable) => p.Modify(manageWebhooks: enable)); - AssertUtil(GuildPermission.ManageEmojis, x => x.ManageEmojisAndStickers, (p, enable) => p.Modify(manageEmojis: enable)); + AssertUtil(GuildPermission.ManageEmojisAndStickers, x => x.ManageEmojisAndStickers, (p, enable) => p.Modify(manageEmojis: enable)); } } } From 152a6c7b56f5ef0b109e89c48ea226f6c9b763af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Sat, 7 Aug 2021 20:56:52 +0200 Subject: [PATCH 11/23] Fix gateway serialization to include nulls (#96) --- src/Discord.Net.Rest/DiscordRestApiClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index 3e9ed4393..5535f4e5c 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -55,7 +55,7 @@ namespace Discord.API _restClientProvider = restClientProvider; UserAgent = userAgent; DefaultRetryMode = defaultRetryMode; - _serializer = serializer ?? new JsonSerializer { ContractResolver = new DiscordContractResolver(), NullValueHandling = NullValueHandling.Ignore }; + _serializer = serializer ?? new JsonSerializer { ContractResolver = new DiscordContractResolver(), NullValueHandling = NullValueHandling.Include }; UseSystemClock = useSystemClock; RequestQueue = new RequestQueue(); From 7a232b22fe626fd530347689612f46ec08748e05 Mon Sep 17 00:00:00 2001 From: MrCakeSlayer <13650699+MrCakeSlayer@users.noreply.github.com> Date: Sat, 7 Aug 2021 14:57:07 -0400 Subject: [PATCH 12/23] Add missing guild permissions (#93) * Update GuildPermissions.cs * Update GuildPermissionsTests.cs --- .../Entities/Permissions/GuildPermissions.cs | 55 +++++++++++++++++-- .../GuildPermissionsTests.cs | 16 +++++- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs b/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs index 1914a6f86..9503e5b3b 100644 --- a/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs +++ b/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs @@ -81,8 +81,20 @@ namespace Discord public bool ManageRoles => Permissions.GetValue(RawValue, GuildPermission.ManageRoles); /// If true, a user may edit the webhooks for this guild. public bool ManageWebhooks => Permissions.GetValue(RawValue, GuildPermission.ManageWebhooks); - /// If true, a user may edit the emojis for this guild. + /// If true, a user may edit the emojis and stickers for this guild. public bool ManageEmojisAndStickers => Permissions.GetValue(RawValue, GuildPermission.ManageEmojisAndStickers); + /// If true, a user may use slash commands in this guild. + public bool UseSlashCommands => Permissions.GetValue(RawValue, GuildPermission.UseSlashCommands); + /// If true, a user may request to speak in stage channels. + public bool RequestToSpeak => Permissions.GetValue(RawValue, GuildPermission.RequestToSpeak); + /// If true, a user may manage threads in this guild. + public bool ManageThreads => Permissions.GetValue(RawValue, GuildPermission.ManageThreads); + /// If true, a user may create public threads in this guild. + public bool UsePublicThreads => Permissions.GetValue(RawValue, GuildPermission.UsePublicThreads); + /// If true, a user may create private threads in this guild. + public bool UsePrivateThreads => Permissions.GetValue(RawValue, GuildPermission.UsePrivateThreads); + /// If true, a user may use external stickers in this guild. + public bool UseExternalStickers => Permissions.GetValue(RawValue, GuildPermission.UseExternalStickers); /// Creates a new with the provided packed value. public GuildPermissions(ulong rawValue) { RawValue = rawValue; } @@ -121,7 +133,13 @@ namespace Discord bool? manageNicknames = null, bool? manageRoles = null, bool? manageWebhooks = null, - bool? manageEmojisAndStickers = null) + bool? manageEmojisAndStickers = null, + bool? useSlashCommands = null, + bool? requestToSpeak = null, + bool? manageThreads = null, + bool? usePublicThreads = null, + bool? usePrivateThreads = null, + bool? useExternalStickers = null) { ulong value = initialValue; @@ -156,6 +174,12 @@ namespace Discord Permissions.SetValue(ref value, manageRoles, GuildPermission.ManageRoles); Permissions.SetValue(ref value, manageWebhooks, GuildPermission.ManageWebhooks); Permissions.SetValue(ref value, manageEmojisAndStickers, GuildPermission.ManageEmojisAndStickers); + Permissions.SetValue(ref value, useSlashCommands, GuildPermission.UseSlashCommands); + Permissions.SetValue(ref value, requestToSpeak, GuildPermission.RequestToSpeak); + Permissions.SetValue(ref value, manageThreads, GuildPermission.ManageThreads); + Permissions.SetValue(ref value, usePublicThreads, GuildPermission.UsePublicThreads); + Permissions.SetValue(ref value, usePrivateThreads, GuildPermission.UseExternalStickers); + Permissions.SetValue(ref value, useExternalStickers, GuildPermission.UseExternalStickers); RawValue = value; } @@ -192,7 +216,13 @@ namespace Discord bool manageNicknames = false, bool manageRoles = false, bool manageWebhooks = false, - bool manageEmojis = false) + bool manageEmojisAndStickers = false, + bool useSlashCommands = false, + bool requestToSpeak = false, + bool manageThreads = false, + bool usePublicThreads = false, + bool usePrivateThreads = false, + bool useExternalStickers = false) : this(0, createInstantInvite: createInstantInvite, manageRoles: manageRoles, @@ -224,7 +254,13 @@ namespace Discord changeNickname: changeNickname, manageNicknames: manageNicknames, manageWebhooks: manageWebhooks, - manageEmojisAndStickers: manageEmojis) + manageEmojisAndStickers: manageEmojisAndStickers, + useSlashCommands: useSlashCommands, + requestToSpeak: requestToSpeak, + manageThreads: manageThreads, + usePublicThreads: usePublicThreads, + usePrivateThreads: usePrivateThreads, + useExternalStickers: useExternalStickers) { } /// Creates a new from this one, changing the provided non-null permissions. @@ -259,11 +295,18 @@ namespace Discord bool? manageNicknames = null, bool? manageRoles = null, bool? manageWebhooks = null, - bool? manageEmojis = null) + bool? manageEmojisAndStickers = null, + bool? useSlashCommands = null, + bool? requestToSpeak = null, + bool? manageThreads = null, + bool? usePublicThreads = null, + bool? usePrivateThreads = null, + bool? useExternalStickers = null) => new GuildPermissions(RawValue, createInstantInvite, kickMembers, banMembers, administrator, manageChannels, manageGuild, addReactions, viewAuditLog, viewGuildInsights, viewChannel, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, moveMembers, - useVoiceActivation, prioritySpeaker, stream, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojis); + useVoiceActivation, prioritySpeaker, stream, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojisAndStickers, + useSlashCommands, requestToSpeak, manageThreads, usePublicThreads, usePrivateThreads, useExternalStickers); /// /// Returns a value that indicates if a specific is enabled diff --git a/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs b/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs index 137dc5575..9be109c6e 100644 --- a/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs +++ b/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs @@ -91,7 +91,13 @@ namespace Discord AssertFlag(() => new GuildPermissions(manageNicknames: true), GuildPermission.ManageNicknames); AssertFlag(() => new GuildPermissions(manageRoles: true), GuildPermission.ManageRoles); AssertFlag(() => new GuildPermissions(manageWebhooks: true), GuildPermission.ManageWebhooks); - AssertFlag(() => new GuildPermissions(manageEmojis: true), GuildPermission.ManageEmojis); + AssertFlag(() => new GuildPermissions(manageEmojisAndStickers: true), GuildPermission.ManageEmojisAndStickers); + AssertFlag(() => new GuildPermissions(useSlashCommands: true), GuildPermission.UseSlashCommands); + AssertFlag(() => new GuildPermissions(requestToSpeak: true), GuildPermission.RequestToSpeak); + AssertFlag(() => new GuildPermissions(manageThreads: true), GuildPermission.ManageThreads); + AssertFlag(() => new GuildPermissions(usePublicThreads: true), GuildPermission.UsePublicThreads); + AssertFlag(() => new GuildPermissions(usePrivateThreads: true), GuildPermission.UsePrivateThreads); + AssertFlag(() => new GuildPermissions(useExternalStickers: true), GuildPermission.UseExternalStickers); } /// @@ -161,7 +167,13 @@ namespace Discord AssertUtil(GuildPermission.ManageNicknames, x => x.ManageNicknames, (p, enable) => p.Modify(manageNicknames: enable)); AssertUtil(GuildPermission.ManageRoles, x => x.ManageRoles, (p, enable) => p.Modify(manageRoles: enable)); AssertUtil(GuildPermission.ManageWebhooks, x => x.ManageWebhooks, (p, enable) => p.Modify(manageWebhooks: enable)); - AssertUtil(GuildPermission.ManageEmojis, x => x.ManageEmojisAndStickers, (p, enable) => p.Modify(manageEmojis: enable)); + AssertUtil(GuildPermission.ManageEmojisAndStickers, x => x.ManageEmojisAndStickers, (p, enable) => p.Modify(manageEmojisAndStickers: enable)); + AssertUtil(GuildPermission.UseSlashCommands, x => x.UseSlashCommands, (p, enable) => p.Modify(useSlashCommands: enable)); + AssertUtil(GuildPermission.RequestToSpeak, x => x.RequestToSpeak, (p, enable) => p.Modify(requestToSpeak: enable)); + AssertUtil(GuildPermission.ManageThreads, x => x.ManageThreads, (p, enable) => p.Modify(manageThreads: enable)); + AssertUtil(GuildPermission.UsePublicThreads, x => x.UsePublicThreads, (p, enable) => p.Modify(usePublicThreads: enable)); + AssertUtil(GuildPermission.UsePrivateThreads, x => x.UsePrivateThreads, (p, enable) => p.Modify(usePrivateThreads: enable)); + AssertUtil(GuildPermission.UseExternalStickers, x => x.UseExternalStickers, (p, enable) => p.Modify(useExternalStickers: enable)); } } } From af9519b0f57e511d15aae0dd26d922d8b3f1cecd Mon Sep 17 00:00:00 2001 From: Nikon <47792796+INikonI@users.noreply.github.com> Date: Sat, 7 Aug 2021 23:57:53 +0500 Subject: [PATCH 13/23] Add banner and accent color to user and some fixes/improvements (#81) * Add banner and accent color to user and some fixes * Fix * Fix! * increase size of user banners to 256 * Some changes and mini refactor of color class * add constant maxDecimalValue to color and checks with exceptions * add `NotSupportedException` for `BannerId` and `AccentColor` in `SocketWebhookUser` * Update ComponentBuilder.cs - `MaxLabelLength` from `ComponentBuilder` moved to `ButtonBuilder` - Added `MaxLabelLength` for `SelectMenuOptionBuilder` - Changed `MaxDescriptionLength` to 100 --- src/Discord.Net.Core/CDN.cs | 18 ++++ .../Message Components/ComponentBuilder.cs | 33 +++--- .../Entities/Permissions/GuildPermissions.cs | 8 +- src/Discord.Net.Core/Entities/Roles/Color.cs | 101 ++++++++++-------- src/Discord.Net.Core/Entities/Users/IUser.cs | 32 +++++- src/Discord.Net.Rest/API/Common/User.cs | 4 + .../Entities/Users/RestThreadUser.cs | 4 +- .../Entities/Users/RestUser.cs | 12 +++ .../Entities/Users/SocketGlobalUser.cs | 4 +- .../Entities/Users/SocketGroupUser.cs | 4 + .../Entities/Users/SocketGuildUser.cs | 7 +- .../Entities/Users/SocketSelfUser.cs | 4 + .../Entities/Users/SocketThreadUser.cs | 16 ++- .../Entities/Users/SocketUnknownUser.cs | 9 +- .../Entities/Users/SocketUser.cs | 18 ++++ .../Entities/Users/SocketWebhookUser.cs | 17 +++ .../GuildPermissionsTests.cs | 4 +- 17 files changed, 222 insertions(+), 73 deletions(-) diff --git a/src/Discord.Net.Core/CDN.cs b/src/Discord.Net.Core/CDN.cs index e1e8e5e1a..b1879eebc 100644 --- a/src/Discord.Net.Core/CDN.cs +++ b/src/Discord.Net.Core/CDN.cs @@ -46,6 +46,24 @@ namespace Discord string extension = FormatToExtension(format, avatarId); return $"{DiscordConfig.CDNUrl}avatars/{userId}/{avatarId}.{extension}?size={size}"; } + + /// + /// Returns a user banner URL. + /// + /// The user snowflake identifier. + /// The banner identifier. + /// The size of the image to return in horizontal pixels. This can be any power of two between 16 and 2048. + /// The format to return. + /// + /// A URL pointing to the user's banner in the specified size. + /// + public static string GetUserBannerUrl(ulong userId, string bannerId, ushort size, ImageFormat format) + { + if (bannerId == null) + return null; + string extension = FormatToExtension(format, bannerId); + return $"{DiscordConfig.CDNUrl}banners/{userId}/{bannerId}.{extension}?size={size}"; + } /// /// Returns the default user avatar URL. /// diff --git a/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs b/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs index bb2f80a81..4027db408 100644 --- a/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs +++ b/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs @@ -10,11 +10,6 @@ namespace Discord /// public class ComponentBuilder { - /// - /// The max length of a . - /// - public const int MaxLabelLength = 80; - /// /// The max length of a . /// @@ -307,17 +302,22 @@ namespace Discord /// public class ButtonBuilder { + /// + /// The max length of a . + /// + public const int MaxLabelLength = 80; + /// /// Gets or sets the label of the current button. /// - /// length exceeds . + /// length exceeds . public string Label { get => _label; set { - if (value != null && value.Length > ComponentBuilder.MaxLabelLength) - throw new ArgumentException(message: $"Button label must be {ComponentBuilder.MaxLabelLength} characters or less!", paramName: nameof(Label)); + if (value != null && value.Length > MaxLabelLength) + throw new ArgumentException(message: $"Button label must be {MaxLabelLength} characters or less!", paramName: nameof(Label)); _label = value; } @@ -539,8 +539,8 @@ namespace Discord if (string.IsNullOrEmpty(this.Url)) throw new InvalidOperationException("Link buttons must have a link associated with them"); else - UrlValidation.Validate(this.Url); - } + UrlValidation.Validate(this.Url); + } else if (string.IsNullOrEmpty(this.CustomId)) throw new InvalidOperationException("Non-link buttons must have a custom id associated with them"); @@ -831,23 +831,28 @@ namespace Discord /// public class SelectMenuOptionBuilder { + /// + /// The maximum length of a . + /// + public const int MaxLabelLength = 100; + /// /// The maximum length of a . /// - public const int MaxDescriptionLength = 50; + public const int MaxDescriptionLength = 100; /// /// Gets or sets the label of the current select menu. /// - /// length exceeds + /// length exceeds public string Label { get => _label; set { if (value != null) - if (value.Length > ComponentBuilder.MaxLabelLength) - throw new ArgumentException(message: $"Button label must be {ComponentBuilder.MaxLabelLength} characters or less!", paramName: nameof(Label)); + if (value.Length > MaxLabelLength) + throw new ArgumentException(message: $"Button label must be {MaxLabelLength} characters or less!", paramName: nameof(Label)); _label = value; } diff --git a/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs b/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs index 1914a6f86..d15297627 100644 --- a/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs +++ b/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs @@ -192,7 +192,7 @@ namespace Discord bool manageNicknames = false, bool manageRoles = false, bool manageWebhooks = false, - bool manageEmojis = false) + bool manageEmojisAndStickers = false) : this(0, createInstantInvite: createInstantInvite, manageRoles: manageRoles, @@ -224,7 +224,7 @@ namespace Discord changeNickname: changeNickname, manageNicknames: manageNicknames, manageWebhooks: manageWebhooks, - manageEmojisAndStickers: manageEmojis) + manageEmojisAndStickers: manageEmojisAndStickers) { } /// Creates a new from this one, changing the provided non-null permissions. @@ -259,11 +259,11 @@ namespace Discord bool? manageNicknames = null, bool? manageRoles = null, bool? manageWebhooks = null, - bool? manageEmojis = null) + bool? manageEmojisAndStickers = null) => new GuildPermissions(RawValue, createInstantInvite, kickMembers, banMembers, administrator, manageChannels, manageGuild, addReactions, viewAuditLog, viewGuildInsights, viewChannel, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, moveMembers, - useVoiceActivation, prioritySpeaker, stream, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojis); + useVoiceActivation, prioritySpeaker, stream, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojisAndStickers); /// /// Returns a value that indicates if a specific is enabled diff --git a/src/Discord.Net.Core/Entities/Roles/Color.cs b/src/Discord.Net.Core/Entities/Roles/Color.cs index 7c2d152a4..ee50710e8 100644 --- a/src/Discord.Net.Core/Entities/Roles/Color.cs +++ b/src/Discord.Net.Core/Entities/Roles/Color.cs @@ -10,68 +10,70 @@ namespace Discord [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public struct Color { + /// Gets the max decimal value of color. + public const uint MaxDecimalValue = 0xFFFFFF; /// Gets the default user color value. - public static readonly Color Default = new Color(0); + public static readonly Color Default = new(0); /// Gets the teal color value. /// A color struct with the hex value of 1ABC9C. - public static readonly Color Teal = new Color(0x1ABC9C); + public static readonly Color Teal = new(0x1ABC9C); /// Gets the dark teal color value. /// A color struct with the hex value of 11806A. - public static readonly Color DarkTeal = new Color(0x11806A); + public static readonly Color DarkTeal = new(0x11806A); /// Gets the green color value. /// A color struct with the hex value of 2ECC71. - public static readonly Color Green = new Color(0x2ECC71); + public static readonly Color Green = new(0x2ECC71); /// Gets the dark green color value. /// A color struct with the hex value of 1F8B4C. - public static readonly Color DarkGreen = new Color(0x1F8B4C); + public static readonly Color DarkGreen = new(0x1F8B4C); /// Gets the blue color value. /// A color struct with the hex value of 3498DB. - public static readonly Color Blue = new Color(0x3498DB); + public static readonly Color Blue = new(0x3498DB); /// Gets the dark blue color value. /// A color struct with the hex value of 206694. - public static readonly Color DarkBlue = new Color(0x206694); + public static readonly Color DarkBlue = new(0x206694); /// Gets the purple color value. /// A color struct with the hex value of 9B59B6. - public static readonly Color Purple = new Color(0x9B59B6); + public static readonly Color Purple = new(0x9B59B6); /// Gets the dark purple color value. /// A color struct with the hex value of 71368A. - public static readonly Color DarkPurple = new Color(0x71368A); + public static readonly Color DarkPurple = new(0x71368A); /// Gets the magenta color value. /// A color struct with the hex value of E91E63. - public static readonly Color Magenta = new Color(0xE91E63); + public static readonly Color Magenta = new(0xE91E63); /// Gets the dark magenta color value. /// A color struct with the hex value of AD1457. - public static readonly Color DarkMagenta = new Color(0xAD1457); + public static readonly Color DarkMagenta = new(0xAD1457); /// Gets the gold color value. /// A color struct with the hex value of F1C40F. - public static readonly Color Gold = new Color(0xF1C40F); + public static readonly Color Gold = new(0xF1C40F); /// Gets the light orange color value. /// A color struct with the hex value of C27C0E. - public static readonly Color LightOrange = new Color(0xC27C0E); + public static readonly Color LightOrange = new(0xC27C0E); /// Gets the orange color value. /// A color struct with the hex value of E67E22. - public static readonly Color Orange = new Color(0xE67E22); + public static readonly Color Orange = new(0xE67E22); /// Gets the dark orange color value. /// A color struct with the hex value of A84300. - public static readonly Color DarkOrange = new Color(0xA84300); + public static readonly Color DarkOrange = new(0xA84300); /// Gets the red color value. /// A color struct with the hex value of E74C3C. - public static readonly Color Red = new Color(0xE74C3C); + public static readonly Color Red = new(0xE74C3C); /// Gets the dark red color value. /// A color struct with the hex value of 992D22. - public static readonly Color DarkRed = new Color(0x992D22); + public static readonly Color DarkRed = new(0x992D22); /// Gets the light grey color value. /// A color struct with the hex value of 979C9F. - public static readonly Color LightGrey = new Color(0x979C9F); + public static readonly Color LightGrey = new(0x979C9F); /// Gets the lighter grey color value. /// A color struct with the hex value of 95A5A6. - public static readonly Color LighterGrey = new Color(0x95A5A6); + public static readonly Color LighterGrey = new(0x95A5A6); /// Gets the dark grey color value. /// A color struct with the hex value of 607D8B. - public static readonly Color DarkGrey = new Color(0x607D8B); + public static readonly Color DarkGrey = new(0x607D8B); /// Gets the darker grey color value. /// A color struct with the hex value of 546E7A. - public static readonly Color DarkerGrey = new Color(0x546E7A); + public static readonly Color DarkerGrey = new(0x546E7A); /// Gets the encoded value for this color. /// @@ -91,22 +93,27 @@ namespace Discord /// Initializes a struct with the given raw value. /// /// - /// The following will create a color that has a hex value of + /// The following will create a color that has a hex value of /// #607D8B. /// /// Color darkGrey = new Color(0x607D8B); /// /// /// The raw value of the color (e.g. 0x607D8B). + /// Value exceeds . public Color(uint rawValue) { + if (rawValue > MaxDecimalValue) + throw new ArgumentException($"{nameof(RawValue)} of color cannot be greater than {MaxDecimalValue}!", nameof(rawValue)); + RawValue = rawValue; } + /// /// Initializes a struct with the given RGB bytes. /// /// - /// The following will create a color that has a value of + /// The following will create a color that has a value of /// #607D8B. /// /// Color darkGrey = new Color((byte)0b_01100000, (byte)0b_01111101, (byte)0b_10001011); @@ -115,19 +122,24 @@ namespace Discord /// The byte that represents the red color. /// The byte that represents the green color. /// The byte that represents the blue color. + /// Value exceeds . public Color(byte r, byte g, byte b) { - RawValue = - ((uint)r << 16) | - ((uint)g << 8) | - (uint)b; + uint value = ((uint)r << 16) + | ((uint)g << 8) + | (uint)b; + + if (value > MaxDecimalValue) + throw new ArgumentException($"{nameof(RawValue)} of color cannot be greater than {MaxDecimalValue}!"); + + RawValue = value; } /// /// Initializes a struct with the given RGB value. /// /// - /// The following will create a color that has a value of + /// The following will create a color that has a value of /// #607D8B. /// /// Color darkGrey = new Color(96, 125, 139); @@ -145,16 +157,15 @@ namespace Discord throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,255]."); if (b < 0 || b > 255) throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,255]."); - RawValue = - ((uint)r << 16) | - ((uint)g << 8) | - (uint)b; + RawValue = ((uint)r << 16) + | ((uint)g << 8) + | (uint)b; } /// /// Initializes a struct with the given RGB float value. /// /// - /// The following will create a color that has a value of + /// The following will create a color that has a value of /// #607c8c. /// /// Color darkGrey = new Color(0.38f, 0.49f, 0.55f); @@ -172,10 +183,9 @@ namespace Discord throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,1]."); if (b < 0.0f || b > 1.0f) throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,1]."); - RawValue = - ((uint)(r * 255.0f) << 16) | - ((uint)(g * 255.0f) << 8) | - (uint)(b * 255.0f); + RawValue = ((uint)(r * 255.0f) << 16) + | ((uint)(g * 255.0f) << 8) + | (uint)(b * 255.0f); } public static bool operator ==(Color lhs, Color rhs) @@ -184,15 +194,22 @@ namespace Discord public static bool operator !=(Color lhs, Color rhs) => lhs.RawValue != rhs.RawValue; + public static implicit operator Color(uint rawValue) + => new(rawValue); + + public static implicit operator uint(Color color) + => color.RawValue; + public override bool Equals(object obj) - => (obj is Color c && RawValue == c.RawValue); + => obj is Color c && RawValue == c.RawValue; public override int GetHashCode() => RawValue.GetHashCode(); - public static implicit operator StandardColor(Color color) => - StandardColor.FromArgb((int)color.RawValue); - public static explicit operator Color(StandardColor color) => - new Color((uint)color.ToArgb() << 8 >> 8); + public static implicit operator StandardColor(Color color) + => StandardColor.FromArgb((int)color.RawValue); + + public static explicit operator Color(StandardColor color) + => new((uint)color.ToArgb() << 8 >> 8); /// /// Gets the hexadecimal representation of the color (e.g. #000ccc). diff --git a/src/Discord.Net.Core/Entities/Users/IUser.cs b/src/Discord.Net.Core/Entities/Users/IUser.cs index 9596a8338..f265bb938 100644 --- a/src/Discord.Net.Core/Entities/Users/IUser.cs +++ b/src/Discord.Net.Core/Entities/Users/IUser.cs @@ -12,17 +12,29 @@ namespace Discord /// string AvatarId { get; } /// + /// Gets the identifier of this user's banner. + /// + string BannerId { get; } + /// + /// Gets the user's banner color. + /// + /// + /// A struct representing the accent color of this user's banner. + /// + Color? AccentColor { get; } + /// /// Gets the avatar URL for this user. /// /// /// This property retrieves a URL for this user's avatar. In event that the user does not have a valid avatar - /// (i.e. their avatar identifier is not set), this property will return null. If you wish to + /// (i.e. their avatar identifier is not set), this method will return null. If you wish to /// retrieve the default avatar for this user, consider using (see /// example). /// /// - /// The following example attempts to retrieve the user's current avatar and send it to a channel; if one is - /// not set, a default avatar for this user will be returned instead. + /// The following example attempts to retrieve the user's current avatar and send it to a channel; if one is + /// not set, a default avatar for this user will be returned instead. /// /// @@ -34,6 +46,16 @@ namespace Discord /// string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128); /// + /// Gets the banner URL for this user. + /// + /// The format to return. + /// The size of the image to return in. This can be any power of two between 16 and 2048. + /// + /// + /// A string representing the user's avatar URL; null if the user does not have an banner in place. + /// + string GetBannerUrl(ImageFormat format = ImageFormat.Auto, ushort size = 256); + /// /// Gets the default avatar URL for this user. /// /// @@ -93,8 +115,8 @@ namespace Discord /// This method is used to obtain or create a channel used to send a direct message. /// /// In event that the current user cannot send a message to the target user, a channel can and will - /// still be created by Discord. However, attempting to send a message will yield a - /// with a 403 as its + /// still be created by Discord. However, attempting to send a message will yield a + /// with a 403 as its /// . There are currently no official workarounds by /// Discord. /// diff --git a/src/Discord.Net.Rest/API/Common/User.cs b/src/Discord.Net.Rest/API/Common/User.cs index d1f436afb..4d1b5b2b7 100644 --- a/src/Discord.Net.Rest/API/Common/User.cs +++ b/src/Discord.Net.Rest/API/Common/User.cs @@ -15,6 +15,10 @@ namespace Discord.API public Optional Bot { get; set; } [JsonProperty("avatar")] public Optional Avatar { get; set; } + [JsonProperty("banner")] + public Optional Banner { get; set; } + [JsonProperty("accent_color")] + public Optional AccentColor { get; set; } //CurrentUser [JsonProperty("verified")] diff --git a/src/Discord.Net.Rest/Entities/Users/RestThreadUser.cs b/src/Discord.Net.Rest/Entities/Users/RestThreadUser.cs index d74591e75..bb981bfdb 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestThreadUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestThreadUser.cs @@ -9,7 +9,7 @@ using Model = Discord.API.ThreadMember; namespace Discord.Rest { /// - /// Represents a thread user recieved over the REST api. + /// Represents a thread user received over the REST api. /// public class RestThreadUser : RestEntity { @@ -51,7 +51,7 @@ namespace Discord.Rest /// Gets the guild user for this thread user. /// /// - /// A task representing the asyncronous get operation. The task returns a + /// A task representing the asynchronous get operation. The task returns a /// that represents the current thread user. /// public Task GetGuildUser() diff --git a/src/Discord.Net.Rest/Entities/Users/RestUser.cs b/src/Discord.Net.Rest/Entities/Users/RestUser.cs index 7bc1447fe..618804fef 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestUser.cs @@ -22,6 +22,10 @@ namespace Discord.Rest /// public string AvatarId { get; private set; } /// + public string BannerId { get; private set; } + /// + public Color? AccentColor { get; private set; } + /// public UserProperties? PublicFlags { get; private set; } /// @@ -61,6 +65,10 @@ namespace Discord.Rest { if (model.Avatar.IsSpecified) AvatarId = model.Avatar.Value; + if (model.Banner.IsSpecified) + BannerId = model.Banner.Value; + if (model.AccentColor.IsSpecified) + AccentColor = model.AccentColor.Value; if (model.Discriminator.IsSpecified) DiscriminatorValue = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture); if (model.Bot.IsSpecified) @@ -92,6 +100,10 @@ namespace Discord.Rest public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) => CDN.GetUserAvatarUrl(Id, AvatarId, size, format); + /// + public string GetBannerUrl(ImageFormat format = ImageFormat.Auto, ushort size = 256) + => CDN.GetUserBannerUrl(Id, BannerId, size, format); + /// public string GetDefaultAvatarUrl() => CDN.GetDefaultUserAvatarUrl(DiscriminatorValue); diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs index 15c5182fc..b1bce5934 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs @@ -12,6 +12,8 @@ namespace Discord.WebSocket public override string Username { get; internal set; } public override ushort DiscriminatorValue { get; internal set; } public override string AvatarId { get; internal set; } + public override string BannerId { get; internal set; } + public override Color? AccentColor { get; internal set; } internal override SocketPresence Presence { get; set; } public override bool IsWebhook => false; @@ -47,7 +49,7 @@ namespace Discord.WebSocket discord.RemoveUser(Id); } } - + internal void Update(ClientState state, PresenceModel model) { Presence = SocketPresence.Create(model); diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs index 805a88110..d99310540 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs @@ -29,6 +29,10 @@ namespace Discord.WebSocket /// public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } /// + public override string BannerId { get { return GlobalUser.BannerId; } internal set { GlobalUser.BannerId = value; } } + /// + public override Color? AccentColor { get { return GlobalUser.AccentColor; } internal set { GlobalUser.AccentColor = value; } } + /// internal override SocketPresence Presence { get { return GlobalUser.Presence; } set { GlobalUser.Presence = value; } } /// diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs index f79fc7afe..ac8409a32 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs @@ -38,6 +38,11 @@ namespace Discord.WebSocket public override ushort DiscriminatorValue { get { return GlobalUser.DiscriminatorValue; } internal set { GlobalUser.DiscriminatorValue = value; } } /// public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } + /// + public override string BannerId { get { return GlobalUser.BannerId; } internal set { GlobalUser.BannerId = value; } } + /// + public override Color? AccentColor { get { return GlobalUser.AccentColor; } internal set { GlobalUser.AccentColor = value; } } + /// public GuildPermissions GuildPermissions => new GuildPermissions(Permissions.ResolveGuild(Guild, this)); internal override SocketPresence Presence { get; set; } @@ -91,7 +96,7 @@ namespace Discord.WebSocket /// Returns the position of the user within the role hierarchy. /// /// - /// The returned value equal to the position of the highest role the user has, or + /// The returned value equal to the position of the highest role the user has, or /// if user is the server owner. /// public int Hierarchy diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs index 7b11257a3..e821238ee 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs @@ -29,6 +29,10 @@ namespace Discord.WebSocket /// public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } /// + public override string BannerId { get { return GlobalUser.BannerId; } internal set { GlobalUser.BannerId = value; } } + /// + public override Color? AccentColor { get { return GlobalUser.AccentColor; } internal set { GlobalUser.AccentColor = value; } } + /// internal override SocketPresence Presence { get { return GlobalUser.Presence; } set { GlobalUser.Presence = value; } } /// public UserProperties Flags { get; internal set; } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs index d1237d598..5fb1f56e5 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs @@ -36,7 +36,7 @@ namespace Discord.WebSocket /// public string Nickname - => GuildUser.Nickname; + => GuildUser.Nickname; /// public DateTimeOffset? PremiumSince @@ -53,6 +53,20 @@ namespace Discord.WebSocket internal set => GuildUser.AvatarId = value; } + /// + public override string BannerId + { + get => GuildUser.BannerId; + internal set => GuildUser.BannerId = value; + } + + /// + public override Color? AccentColor + { + get => GuildUser.AccentColor; + internal set => GuildUser.AccentColor = value; + } + /// public override ushort DiscriminatorValue { diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs index 840a1c30b..180e60a3b 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs @@ -19,9 +19,16 @@ namespace Discord.WebSocket public override ushort DiscriminatorValue { get; internal set; } /// public override string AvatarId { get; internal set; } + + /// + public override string BannerId { get; internal set; } + + /// + public override Color? AccentColor { get; internal set; } + /// public override bool IsBot { get; internal set; } - + /// public override bool IsWebhook => false; /// diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs index 025daf29a..c50fbee4f 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs @@ -25,6 +25,10 @@ namespace Discord.WebSocket /// public abstract string AvatarId { get; internal set; } /// + public abstract string BannerId { get; internal set; } + /// + public abstract Color? AccentColor { get; internal set; } + /// public abstract bool IsWebhook { get; } /// public UserProperties? PublicFlags { get; private set; } @@ -64,6 +68,16 @@ namespace Discord.WebSocket AvatarId = model.Avatar.Value; hasChanges = true; } + if (model.Banner.IsSpecified && model.Banner.Value != BannerId) + { + BannerId = model.Banner.Value; + hasChanges = true; + } + if (model.AccentColor.IsSpecified && model.AccentColor.Value != AccentColor?.RawValue) + { + AccentColor = model.AccentColor.Value; + hasChanges = true; + } if (model.Discriminator.IsSpecified) { var newVal = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture); @@ -99,6 +113,10 @@ namespace Discord.WebSocket public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) => CDN.GetUserAvatarUrl(Id, AvatarId, size, format); + /// + public string GetBannerUrl(ImageFormat format = ImageFormat.Auto, ushort size = 256) + => CDN.GetUserBannerUrl(Id, BannerId, size, format); + /// public string GetDefaultAvatarUrl() => CDN.GetDefaultUserAvatarUrl(DiscriminatorValue); diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs index 2b0ecbb19..f1269e649 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs @@ -24,6 +24,23 @@ namespace Discord.WebSocket public override ushort DiscriminatorValue { get; internal set; } /// public override string AvatarId { get; internal set; } + + /// + /// Webhook users does not support banners. + public override string BannerId + { + get => throw new NotSupportedException("Webhook users does not support banners."); + internal set => throw new NotSupportedException("Webhook users does not support banners."); + } + + /// + /// Webhook users does not support accent colors. + public override Color? AccentColor + { + get => throw new NotSupportedException("Webhook users does not support accent colors."); + internal set => throw new NotSupportedException("Webhook users does not support accent colors."); + } + /// public override bool IsBot { get; internal set; } diff --git a/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs b/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs index bb841fd1b..7ff17ac04 100644 --- a/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs +++ b/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs @@ -91,7 +91,7 @@ namespace Discord AssertFlag(() => new GuildPermissions(manageNicknames: true), GuildPermission.ManageNicknames); AssertFlag(() => new GuildPermissions(manageRoles: true), GuildPermission.ManageRoles); AssertFlag(() => new GuildPermissions(manageWebhooks: true), GuildPermission.ManageWebhooks); - AssertFlag(() => new GuildPermissions(manageEmojis: true), GuildPermission.ManageEmojisAndStickers); + AssertFlag(() => new GuildPermissions(manageEmojisAndStickers: true), GuildPermission.ManageEmojisAndStickers); } /// @@ -161,7 +161,7 @@ namespace Discord AssertUtil(GuildPermission.ManageNicknames, x => x.ManageNicknames, (p, enable) => p.Modify(manageNicknames: enable)); AssertUtil(GuildPermission.ManageRoles, x => x.ManageRoles, (p, enable) => p.Modify(manageRoles: enable)); AssertUtil(GuildPermission.ManageWebhooks, x => x.ManageWebhooks, (p, enable) => p.Modify(manageWebhooks: enable)); - AssertUtil(GuildPermission.ManageEmojisAndStickers, x => x.ManageEmojisAndStickers, (p, enable) => p.Modify(manageEmojis: enable)); + AssertUtil(GuildPermission.ManageEmojisAndStickers, x => x.ManageEmojisAndStickers, (p, enable) => p.Modify(manageEmojisAndStickers: enable)); } } } From c3580fd8931ff57be660da77a779ef0be2d6bc6c Mon Sep 17 00:00:00 2001 From: Cenk Ergen <57065323+Cenngo@users.noreply.github.com> Date: Sun, 8 Aug 2021 19:53:55 +0300 Subject: [PATCH 14/23] Interface Method Declarations for Interaction Methods (#99) * added interface method declarations * inline docs --- src/Discord.Net.Core/Discord.Net.Core.xml | 121 ++++++++++++++++-- .../Entities/Guilds/IGuild.cs | 10 ++ .../Interactions/IApplicationCommand.cs | 9 +- .../Interactions/IDiscordInteraction.cs | 54 ++++++++ src/Discord.Net.Rest/Discord.Net.Rest.xml | 13 ++ .../Entities/Guilds/RestGuild.cs | 15 +++ .../Discord.Net.WebSocket.xml | 28 +++- .../Entities/Guilds/SocketGuild.cs | 3 + .../Entities/Interaction/SocketInteraction.cs | 15 +++ 9 files changed, 243 insertions(+), 25 deletions(-) diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml index 1ab7ab78d..dfbb2fc50 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.xml +++ b/src/Discord.Net.Core/Discord.Net.Core.xml @@ -3723,6 +3723,16 @@ A task that represents the asynchronous removal operation. + + + Gets this guilds slash commands commands + + 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 application commands found within the guild. + + Holds information for a guild integration feature. @@ -4293,13 +4303,6 @@ If the option is a subcommand or subcommand group type, this nested options will be the parameters. - - - Deletes this command - - The options to be used when sending the request. - A task that represents the asynchronous delete operation. - Represents data of an Interaction Command, see . @@ -4433,6 +4436,58 @@ read-only property, always 1. + + + Responds to an Interaction with type . + + The text of the message to be sent. + A array of embeds to send with this response. Max 10 + if the message should be read out by a text-to-speech reader, otherwise . + if the response should be hidden to everyone besides the invoker of the command, otherwise . + The allowed mentions for this response. + The request options for this response. + A to be sent with this response + A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + + + + Sends a followup message for this interaction. + + The text of the message to be sent + A array of embeds to send with this response. Max 10 + if the message should be read out by a text-to-speech reader, otherwise . + if the response should be hidden to everyone besides the invoker of the command, otherwise . + The allowed mentions for this response. + The request options for this response. + A to be sent with this response + A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + + The sent message. + + + + + Gets the original response for this interaction. + + The request options for this async request. + A that represents the initial response. + + + + Edits original response for this interaction. + + A delegate containing the properties to modify the message with. + The request options for this async request. + A that represents the initial response. + + + + Acknowledges this interaction. + + + A task that represents the asynchronous operation of acknowledging the interaction. + + Represents an interface used to specify classes that they are a vaild dataype of a class. @@ -4583,7 +4638,7 @@ Represents a builder for creating a . - + The max length of a . @@ -4710,7 +4765,7 @@ Gets or sets the label of the current button. - length exceeds . + length exceeds . @@ -5035,11 +5090,16 @@ The maximum length of a . + + + The maximum length of a . + + Gets or sets the label of the current select menu. - length exceeds + length exceeds @@ -7554,10 +7614,38 @@ The message for when a news channel subscription is added to a text channel. + + + The message for when a guild is disqualified from discovery. + + + + + The message for when a guild is requalified for discovery. + + + + + The message for when the initial warning is sent for the initial grace period discovery. + + + + + The message for when the final warning is sent for the initial grace period discovery. + + + + + The message for when a thread is created. + + The message is an inline reply. + + Only available in API v8 + @@ -7567,6 +7655,19 @@ Only available in API v8 + + + The message that starts a thread. + + + Only available in API v9 + + + + + The message for a invite reminder + + A metadata containing reaction information. diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs index b8fd858df..fb26bdd36 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs @@ -892,5 +892,15 @@ namespace Discord /// A task that represents the asynchronous removal operation. /// Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null); + + /// + /// Gets this guilds slash commands commands + /// + /// 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 application commands found within the guild. + /// + Task> GetApplicationCommandsAsync (RequestOptions options = null); } } diff --git a/src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs index eb61c539f..a1a33acea 100644 --- a/src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs +++ b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs @@ -9,7 +9,7 @@ namespace Discord /// /// The base command model that belongs to an application. see /// - public interface IApplicationCommand : ISnowflakeEntity + public interface IApplicationCommand : ISnowflakeEntity, IDeletable { /// /// Gets the unique id of the parent application. @@ -35,12 +35,5 @@ namespace Discord /// If the option is a subcommand or subcommand group type, this nested options will be the parameters. /// IReadOnlyCollection Options { get; } - - /// - /// Deletes this command - /// - /// The options to be used when sending the request. - /// A task that represents the asynchronous delete operation. - Task DeleteAsync(RequestOptions options = null); } } diff --git a/src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs b/src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs index 466bf3e91..b5afddca2 100644 --- a/src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs +++ b/src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs @@ -39,5 +39,59 @@ namespace Discord /// read-only property, always 1. /// int Version { get; } + + /// + /// Responds to an Interaction with type . + /// + /// The text of the message to be sent. + /// A array of embeds to send with this response. Max 10 + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + Task RespondAsync (string text = null, Embed[] embeds = null, bool isTTS = false, + bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); + + /// + /// Sends a followup message for this interaction. + /// + /// The text of the message to be sent + /// A array of embeds to send with this response. Max 10 + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// + /// The sent message. + /// + Task FollowupAsync (string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, + AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); + + /// + /// Gets the original response for this interaction. + /// + /// The request options for this async request. + /// A that represents the initial response. + Task GetOriginalResponseAsync (RequestOptions options = null); + + /// + /// Edits original response for this interaction. + /// + /// A delegate containing the properties to modify the message with. + /// The request options for this async request. + /// A that represents the initial response. + Task ModifyOriginalResponseAsync (Action func, RequestOptions options = null); + + /// + /// Acknowledges this interaction. + /// + /// + /// A task that represents the asynchronous operation of acknowledging the interaction. + /// + Task DeferAsync (RequestOptions options = null); } } diff --git a/src/Discord.Net.Rest/Discord.Net.Rest.xml b/src/Discord.Net.Rest/Discord.Net.Rest.xml index eda180f01..a9630f382 100644 --- a/src/Discord.Net.Rest/Discord.Net.Rest.xml +++ b/src/Discord.Net.Rest/Discord.Net.Rest.xml @@ -3403,6 +3403,16 @@ of webhooks found within the guild. + + + Gets this guilds slash commands commands + + 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 application commands found within the guild. + + Returns the name of the guild. @@ -3548,6 +3558,9 @@ + + + diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs index 37491909c..9c6f6011e 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs @@ -808,6 +808,18 @@ namespace Discord.Rest public Task> GetWebhooksAsync(RequestOptions options = null) => GuildHelper.GetWebhooksAsync(this, Discord, options); + //Interactions + /// + /// Gets this guilds slash commands commands + /// + /// 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 application commands found within the guild. + /// + public async Task> GetApplicationCommandsAsync (RequestOptions options = null) + => await ClientHelper.GetGuildApplicationCommands(Discord, Id, options).ConfigureAwait(false); + /// /// Returns the name of the guild. /// @@ -1061,5 +1073,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); } } diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml index b17f73024..72ec97e58 100644 --- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml +++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml @@ -3477,6 +3477,9 @@ + + + Represents a Websocket-based interaction type for Message Components. @@ -3492,7 +3495,7 @@ The message that contained the trigger for this interaction. - + @@ -3503,7 +3506,7 @@ The request options for this async request. A task that represents the asynchronous operation of updating the message. - + @@ -3619,10 +3622,10 @@ The data associated with this interaction. - + - + @@ -3708,12 +3711,12 @@ if the token is valid for replying to, otherwise . - + Responds to an Interaction with type . If you have set to , You should use - instead. + instead. The text of the message to be sent. @@ -3723,10 +3726,11 @@ The allowed mentions for this response. The request options for this response. A to be sent with this response + A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. Message content is too long, length must be less or equal to . The parameters provided were invalid or the token was invalid. - + Sends a followup message for this interaction. @@ -3737,6 +3741,7 @@ The allowed mentions for this response. The request options for this response. A to be sent with this response + A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. The sent message. @@ -3772,6 +3777,15 @@ A task that represents the asynchronous operation of acknowledging the interaction. + + + + + + + + + Represents a WebSocket-based invite to a guild. diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index f720db018..ce188e707 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -1436,6 +1436,9 @@ 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); void IDisposable.Dispose() { diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs index 4b2e3baec..5547fed1e 100644 --- a/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs @@ -171,5 +171,20 @@ namespace Discord.WebSocket // Tokens last for 15 minutes according to https://discord.com/developers/docs/interactions/slash-commands#responding-to-an-interaction return (DateTime.UtcNow - this.CreatedAt.UtcDateTime).TotalMinutes <= 15d; } + + // IDiscordInteraction + + /// + async Task IDiscordInteraction.FollowupAsync (string text, Embed[] embeds, bool isTTS, bool ephemeral, AllowedMentions allowedMentions, + RequestOptions options, MessageComponent component, Embed embed) + => await FollowupAsync(text, embeds, isTTS, ephemeral, allowedMentions, options, component, embed).ConfigureAwait(false); + + /// + async Task IDiscordInteraction.GetOriginalResponseAsync (RequestOptions options) + => await GetOriginalResponseAsync(options).ConfigureAwait(false); + + /// + async Task IDiscordInteraction.ModifyOriginalResponseAsync (Action func, RequestOptions options) + => await ModifyOriginalResponseAsync(func, options).ConfigureAwait(false); } } From cc5fc8d288a8b786e9f8209f195ca841166e3764 Mon Sep 17 00:00:00 2001 From: quin lynch Date: Sun, 8 Aug 2021 13:56:01 -0300 Subject: [PATCH 15/23] Fix serialization error --- src/Discord.Net.Rest/API/Common/Game.cs | 4 ++-- .../Discord.Net.WebSocket.xml | 10 ++++++++++ .../DiscordSocketApiClient.cs | 17 ++++++++++++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/Discord.Net.Rest/API/Common/Game.cs b/src/Discord.Net.Rest/API/Common/Game.cs index 294b0c7fd..775b6aabc 100644 --- a/src/Discord.Net.Rest/API/Common/Game.cs +++ b/src/Discord.Net.Rest/API/Common/Game.cs @@ -41,8 +41,8 @@ namespace Discord.API public Optional Emoji { get; set; } [JsonProperty("created_at")] public Optional CreatedAt { get; set; } - [JsonProperty("buttons")] - public Optional Buttons { get; set; } + //[JsonProperty("buttons")] + //public Optional Buttons { get; set; } [OnError] internal void OnError(StreamingContext context, ErrorContext errorContext) diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml index 576fcc5f0..6a41708c8 100644 --- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml +++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml @@ -3628,6 +3628,16 @@ + + + Defers an interaction and responds with type 5 () + + to send this message ephemerally, otherwise . + The request options for this async request. + + A task that represents the asynchronous operation of acknowledging the interaction. + + diff --git a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs index a862b5778..11ecc0867 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs @@ -79,7 +79,7 @@ namespace Discord.API if (msg != null) { #if DEBUG_PACKETS - Console.WriteLine($"<- {msg.Operation} [{msg.Type ?? "none"}] : {(msg.Payload as Newtonsoft.Json.Linq.JToken)?.ToString().Length}"); + Console.WriteLine($"<- {(GatewayOpCode)msg.Operation} [{msg.Type ?? "none"}] : {(msg.Payload as Newtonsoft.Json.Linq.JToken)?.ToString().Length}"); #endif await _receivedGatewayEvent.InvokeAsync((GatewayOpCode)msg.Operation, msg.Sequence, msg.Type, msg.Payload).ConfigureAwait(false); @@ -96,7 +96,7 @@ namespace Discord.API if (msg != null) { #if DEBUG_PACKETS - Console.WriteLine($"<- {msg.Operation} [{msg.Type ?? "none"}] : {(msg.Payload as Newtonsoft.Json.Linq.JToken)?.ToString().Length}"); + Console.WriteLine($"<- {(GatewayOpCode)msg.Operation} [{msg.Type ?? "none"}] : {(msg.Payload as Newtonsoft.Json.Linq.JToken)?.ToString().Length}"); #endif await _receivedGatewayEvent.InvokeAsync((GatewayOpCode)msg.Operation, msg.Sequence, msg.Type, msg.Payload).ConfigureAwait(false); @@ -105,6 +105,10 @@ namespace Discord.API }; WebSocketClient.Closed += async ex => { +#if DEBUG_PACKETS + Console.WriteLine(ex); +#endif + await DisconnectAsync().ConfigureAwait(false); await _disconnectedEvent.InvokeAsync(ex).ConfigureAwait(false); }; @@ -166,6 +170,11 @@ namespace Discord.API var gatewayResponse = await GetGatewayAsync().ConfigureAwait(false); _gatewayUrl = $"{gatewayResponse.Url}?v={DiscordConfig.APIVersion}&encoding={DiscordSocketConfig.GatewayEncoding}&compress=zlib-stream"; } + +#if DEBUG + Console.WriteLine("Connecting to gateway: " + _gatewayUrl); +#endif + await WebSocketClient.ConnectAsync(_gatewayUrl).ConfigureAwait(false); ConnectionState = ConnectionState.Connected; @@ -237,7 +246,9 @@ namespace Discord.API options = RequestOptions.CreateOrClone(options); var props = new Dictionary { - ["$device"] = "Discord.Net Labs" + ["$device"] = "Discord.Net Labs", + ["$os"] = Environment.OSVersion.Platform.ToString(), + [$"browser"] = "Discord.Net Labs" }; var msg = new IdentifyParams() { From f98d742909683f1fe0f0926bf78b9cee0243d7ad Mon Sep 17 00:00:00 2001 From: quin lynch Date: Sun, 8 Aug 2021 14:06:06 -0300 Subject: [PATCH 16/23] meta: bump versions --- src/Discord.Net.Core/Discord.Net.Core.csproj | 6 +- src/Discord.Net.Core/Discord.Net.Core.xml | 103 ++++++++++++++---- src/Discord.Net.Rest/Discord.Net.Rest.csproj | 6 +- src/Discord.Net.Rest/Discord.Net.Rest.xml | 13 ++- .../Discord.Net.WebSocket.csproj | 4 +- .../Discord.Net.WebSocket.xml | 49 ++++++++- src/Discord.Net/Discord.Net.nuspec | 20 ++-- 7 files changed, 162 insertions(+), 39 deletions(-) diff --git a/src/Discord.Net.Core/Discord.Net.Core.csproj b/src/Discord.Net.Core/Discord.Net.Core.csproj index f0be10059..309c45fb6 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.csproj +++ b/src/Discord.Net.Core/Discord.Net.Core.csproj @@ -8,12 +8,12 @@ net461;netstandard2.0;netstandard2.1 netstandard2.0;netstandard2.1 Discord.Net.Labs.Core - 3.0.0-pre + 3.0.1-pre Discord.Net.Labs.Core https://github.com/Discord-Net-Labs/Discord.Net-Labs Temporary.png - 2.3.8 - 2.3.8 + 3.3.1 + 3.0.1 false diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml index b41bdd2f8..582210832 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.xml +++ b/src/Discord.Net.Core/Discord.Net.Core.xml @@ -100,6 +100,18 @@ A URL pointing to the user's avatar in the specified size. + + + Returns a user banner URL. + + The user snowflake identifier. + The banner identifier. + The size of the image to return in horizontal pixels. This can be any power of two between 16 and 2048. + The format to return. + + A URL pointing to the user's banner in the specified size. + + Returns the default user avatar URL. @@ -4782,11 +4794,6 @@ Represents a builder for creating a . - - - The max length of a . - - The max length of a . @@ -4905,11 +4912,16 @@ Represents a class used to build 's. + + + The max length of a . + + Gets or sets the label of the current button. - length exceeds . + length exceeds . @@ -5229,6 +5241,11 @@ Represents a class used to build 's. + + + The maximum length of a . + + The maximum length of a . @@ -5238,7 +5255,7 @@ Gets or sets the label of the current select menu. - length exceeds + length exceeds @@ -8645,7 +8662,25 @@ If true, a user may edit the webhooks for this guild. - If true, a user may edit the emojis for this guild. + If true, a user may edit the emojis and stickers for this guild. + + + If true, a user may use slash commands in this guild. + + + If true, a user may request to speak in stage channels. + + + If true, a user may manage threads in this guild. + + + If true, a user may create public threads in this guild. + + + If true, a user may create private threads in this guild. + + + If true, a user may use external stickers in this guild. Creates a new with the provided packed value. @@ -8653,10 +8688,10 @@ Creates a new with the provided packed value after converting to ulong. - + Creates a new structure with the provided permissions. - + Creates a new from this one, changing the provided non-null permissions. @@ -8843,6 +8878,9 @@ Represents a color used in Discord. + + Gets the max decimal value of color. + Gets the default user color value. @@ -8947,20 +8985,21 @@ Initializes a struct with the given raw value. - The following will create a color that has a hex value of + The following will create a color that has a hex value of #607D8B. Color darkGrey = new Color(0x607D8B); The raw value of the color (e.g. 0x607D8B). + Value exceeds . Initializes a struct with the given RGB bytes. - The following will create a color that has a value of + The following will create a color that has a value of #607D8B. Color darkGrey = new Color((byte)0b_01100000, (byte)0b_01111101, (byte)0b_10001011); @@ -8969,13 +9008,14 @@ The byte that represents the red color. The byte that represents the green color. The byte that represents the blue color. + Value exceeds . Initializes a struct with the given RGB value. - The following will create a color that has a value of + The following will create a color that has a value of #607D8B. Color darkGrey = new Color(96, 125, 139); @@ -8991,7 +9031,7 @@ Initializes a struct with the given RGB float value. - The following will create a color that has a value of + The following will create a color that has a value of #607c8c. Color darkGrey = new Color(0.38f, 0.49f, 0.55f); @@ -9759,19 +9799,33 @@ Gets the identifier of this user's avatar. + + + Gets the identifier of this user's banner. + + + + + Gets the user's banner color. + + + A struct representing the accent color of this user's banner. + + Gets the avatar URL for this user. This property retrieves a URL for this user's avatar. In event that the user does not have a valid avatar - (i.e. their avatar identifier is not set), this property will return null. If you wish to + (i.e. their avatar identifier is not set), this method will return null. If you wish to retrieve the default avatar for this user, consider using (see example). - The following example attempts to retrieve the user's current avatar and send it to a channel; if one is - not set, a default avatar for this user will be returned instead. + The following example attempts to retrieve the user's current avatar and send it to a channel; if one is + not set, a default avatar for this user will be returned instead. @@ -9782,6 +9836,17 @@ A string representing the user's avatar URL; null if the user does not have an avatar in place. + + + Gets the banner URL for this user. + + The format to return. + The size of the image to return in. This can be any power of two between 16 and 2048. + + + A string representing the user's avatar URL; null if the user does not have an banner in place. + + Gets the default avatar URL for this user. @@ -9849,8 +9914,8 @@ This method is used to obtain or create a channel used to send a direct message. In event that the current user cannot send a message to the target user, a channel can and will - still be created by Discord. However, attempting to send a message will yield a - with a 403 as its + still be created by Discord. However, attempting to send a message will yield a + with a 403 as its . There are currently no official workarounds by Discord. diff --git a/src/Discord.Net.Rest/Discord.Net.Rest.csproj b/src/Discord.Net.Rest/Discord.Net.Rest.csproj index b1efafae2..16b165575 100644 --- a/src/Discord.Net.Rest/Discord.Net.Rest.csproj +++ b/src/Discord.Net.Rest/Discord.Net.Rest.csproj @@ -9,11 +9,11 @@ netstandard2.0;netstandard2.1 Temporary.png https://github.com/Discord-Net-Labs/Discord.Net-Labs - 3.0.0-pre + 3.0.1-pre Discord.Net.Labs.Rest https://github.com/Discord-Net-Labs/Discord.Net-Labs - 2.3.4 - 2.3.4 + 3.0.1 + 3.0.1 ..\Discord.Net.Rest\Discord.Net.Rest.xml diff --git a/src/Discord.Net.Rest/Discord.Net.Rest.xml b/src/Discord.Net.Rest/Discord.Net.Rest.xml index a594fc985..5d1949650 100644 --- a/src/Discord.Net.Rest/Discord.Net.Rest.xml +++ b/src/Discord.Net.Rest/Discord.Net.Rest.xml @@ -4570,7 +4570,7 @@ - Represents a thread user recieved over the REST api. + Represents a thread user received over the REST api. @@ -4593,7 +4593,7 @@ Gets the guild user for this thread user. - A task representing the asyncronous get operation. The task returns a + A task representing the asynchronous get operation. The task returns a that represents the current thread user. @@ -4614,6 +4614,12 @@ + + + + + + @@ -4656,6 +4662,9 @@ + + + diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj index af17578fb..167ccebb0 100644 --- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj +++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj @@ -8,7 +8,7 @@ net461;netstandard2.0;netstandard2.1 netstandard2.0;netstandard2.1 true - 3.0.0-pre + 3.0.1-pre https://github.com/Discord-Net-Labs/Discord.Net-Labs https://github.com/Discord-Net-Labs/Discord.Net-Labs Temporary.png @@ -16,6 +16,8 @@ ..\Discord.Net.WebSocket\Discord.Net.WebSocket.xml + 3.0.1 + 3.0.1 TRACE; diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml index 6a41708c8..62019eab2 100644 --- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml +++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml @@ -4433,6 +4433,12 @@ + + + + + + @@ -4491,6 +4497,12 @@ + + + + + + @@ -4554,7 +4566,7 @@ Returns the position of the user within the role hierarchy. - The returned value equal to the position of the highest role the user has, or + The returned value equal to the position of the highest role the user has, or if user is the server owner. @@ -4676,6 +4688,12 @@ + + + + + + @@ -4729,6 +4747,12 @@ + + + + + + @@ -4836,6 +4860,12 @@ + + + + + + @@ -4866,6 +4896,12 @@ + + + + + + @@ -4904,6 +4940,9 @@ + + + @@ -4985,6 +5024,14 @@ + + + Webhook users does not support banners. + + + + Webhook users does not support accent colors. + diff --git a/src/Discord.Net/Discord.Net.nuspec b/src/Discord.Net/Discord.Net.nuspec index 595203eba..eb3bd9b6d 100644 --- a/src/Discord.Net/Discord.Net.nuspec +++ b/src/Discord.Net/Discord.Net.nuspec @@ -2,7 +2,7 @@ Discord.Net.Labs - 3.0.1-pre$suffix$ + 3.0.2-pre$suffix$ Discord.Net Labs Discord.Net Contributors quinchs @@ -14,23 +14,23 @@ https://avatars.githubusercontent.com/u/84047264 - - - + + + - - - + + + - - - + + + From 345f06845a71975383477df63b3db7dffe906e00 Mon Sep 17 00:00:00 2001 From: quin lynch Date: Sun, 8 Aug 2021 14:30:57 -0300 Subject: [PATCH 17/23] Fix debug pragma --- src/Discord.Net.WebSocket/DiscordSocketApiClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs index 11ecc0867..e19cedb33 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs @@ -171,7 +171,7 @@ namespace Discord.API _gatewayUrl = $"{gatewayResponse.Url}?v={DiscordConfig.APIVersion}&encoding={DiscordSocketConfig.GatewayEncoding}&compress=zlib-stream"; } -#if DEBUG +#if DEBUG_PACKETS Console.WriteLine("Connecting to gateway: " + _gatewayUrl); #endif From 4d1ddf8999abf55bda6abc5029f4fab49f182d75 Mon Sep 17 00:00:00 2001 From: quin lynch Date: Sun, 8 Aug 2021 17:00:13 -0300 Subject: [PATCH 18/23] meta: bump version --- src/Discord.Net.Webhook/Discord.Net.Webhook.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Discord.Net.Webhook/Discord.Net.Webhook.csproj b/src/Discord.Net.Webhook/Discord.Net.Webhook.csproj index 13e5cf111..f04dedf43 100644 --- a/src/Discord.Net.Webhook/Discord.Net.Webhook.csproj +++ b/src/Discord.Net.Webhook/Discord.Net.Webhook.csproj @@ -6,7 +6,7 @@ Discord.Webhook A core Discord.Net Labs library containing the Webhook client and models. netstandard2.0;netstandard2.1 - 2.3.4 + 3.0.0-pre Discord.Net.Labs.Webhook https://github.com/Discord-Net-Labs/Discord.Net-Labs https://github.com/Discord-Net-Labs/Discord.Net-Labs From 1b05238d3353a16e6f96c24d7594bfcb995c3e45 Mon Sep 17 00:00:00 2001 From: quin lynch Date: Mon, 9 Aug 2021 18:29:55 -0300 Subject: [PATCH 19/23] Remove rich presence button --- .../API/Common/RichPresenceButton.cs | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 src/Discord.Net.Rest/API/Common/RichPresenceButton.cs diff --git a/src/Discord.Net.Rest/API/Common/RichPresenceButton.cs b/src/Discord.Net.Rest/API/Common/RichPresenceButton.cs deleted file mode 100644 index 66f34c82e..000000000 --- a/src/Discord.Net.Rest/API/Common/RichPresenceButton.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Discord.API -{ - internal class RichPresenceButton - { - [JsonProperty("label")] - public string Label { get; set; } - - [JsonProperty("url")] - public string Url { get; set; } - } -} From 07962445072e57f231a531f237e01f859fc95871 Mon Sep 17 00:00:00 2001 From: Cenk Ergen <57065323+Cenngo@users.noreply.github.com> Date: Wed, 11 Aug 2021 03:49:25 +0300 Subject: [PATCH 20/23] Assign CurrentUserId in Sharded Client (#100) * added interface method declarations * inline docs * current user id assignment in sharded client --- src/Discord.Net.WebSocket/DiscordShardedClient.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Discord.Net.WebSocket/DiscordShardedClient.cs b/src/Discord.Net.WebSocket/DiscordShardedClient.cs index 386f9f7e5..99a60607a 100644 --- a/src/Discord.Net.WebSocket/DiscordShardedClient.cs +++ b/src/Discord.Net.WebSocket/DiscordShardedClient.cs @@ -30,7 +30,16 @@ namespace Discord.WebSocket /// public override IActivity Activity { get => _shards[0].Activity; protected set { } } - internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; + internal new DiscordSocketApiClient ApiClient + { + get + { + if (base.ApiClient.CurrentUserId == null) + base.ApiClient.CurrentUserId = CurrentUser?.Id; + + return base.ApiClient; + } + } /// public override IReadOnlyCollection Guilds => GetGuilds().ToReadOnlyCollection(GetGuildCount); /// From 82d6eda8082f67d2d8dc0ae0fe6bff7f97ae404f Mon Sep 17 00:00:00 2001 From: d4n3436 Date: Tue, 10 Aug 2021 22:15:17 -0500 Subject: [PATCH 21/23] Allow EmbedBuilder.ImageUrl to use attachment scheme syntax (#104) --- src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs b/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs index 2ab2699a6..5b92e02a5 100644 --- a/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs +++ b/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs @@ -411,7 +411,7 @@ namespace Discord UrlValidation.Validate(Url); if (!string.IsNullOrEmpty(ThumbnailUrl)) UrlValidation.Validate(ThumbnailUrl); - if (!string.IsNullOrEmpty(ImageUrl)) + if (!string.IsNullOrEmpty(ImageUrl) && !ImageUrl.StartsWith("attachment://", StringComparison.Ordinal)) UrlValidation.Validate(ImageUrl); if (Author != null) { From 2435b873c797dba329e1c0a394055881d38a17a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Thu, 19 Aug 2021 06:57:08 +0200 Subject: [PATCH 22/23] Make Webhook ApplicationId nullable instead of optional + fix IDiscordInteraction DeferAsync method (#110) * Make Webhook ApplicationId nullable instead of optional * Fix IDiscordInteraction DeferAsync to account for ephemeral defer --- src/Discord.Net.Core/Discord.Net.Core.xml | 2 +- .../Entities/Interactions/IDiscordInteraction.cs | 2 +- src/Discord.Net.Rest/API/Common/Webhook.cs | 2 +- src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs | 4 ++-- .../Entities/Webhooks/RestInternalWebhook.cs | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml index 803127009..94b0c5cf6 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.xml +++ b/src/Discord.Net.Core/Discord.Net.Core.xml @@ -4691,7 +4691,7 @@ The request options for this async request. A that represents the initial response. - + Acknowledges this interaction. diff --git a/src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs b/src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs index b5afddca2..ae015c2a6 100644 --- a/src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs +++ b/src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs @@ -92,6 +92,6 @@ namespace Discord /// /// A task that represents the asynchronous operation of acknowledging the interaction. /// - Task DeferAsync (RequestOptions options = null); + Task DeferAsync (bool ephemeral = false, RequestOptions options = null); } } diff --git a/src/Discord.Net.Rest/API/Common/Webhook.cs b/src/Discord.Net.Rest/API/Common/Webhook.cs index ff1dca9bd..eb504a27c 100644 --- a/src/Discord.Net.Rest/API/Common/Webhook.cs +++ b/src/Discord.Net.Rest/API/Common/Webhook.cs @@ -22,6 +22,6 @@ namespace Discord.API [JsonProperty("user")] public Optional Creator { get; set; } [JsonProperty("application_id")] - public Optional ApplicationId { get; set; } + public ulong? ApplicationId { get; set; } } } diff --git a/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs b/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs index 0d24f08df..5ae09fde0 100644 --- a/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs +++ b/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs @@ -68,8 +68,8 @@ namespace Discord.Rest GuildId = model.GuildId.Value; if (model.Name.IsSpecified) Name = model.Name.Value; - if (model.ApplicationId.IsSpecified) - ApplicationId = model.ApplicationId.Value; + + ApplicationId = model.ApplicationId; } /// diff --git a/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs b/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs index 210d8eda0..2a5c4786e 100644 --- a/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs +++ b/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs @@ -45,8 +45,8 @@ namespace Discord.Webhook GuildId = model.GuildId.Value; if (model.Name.IsSpecified) Name = model.Name.Value; - if (model.ApplicationId.IsSpecified) - ApplicationId = model.ApplicationId.Value; + + ApplicationId = model.ApplicationId; } public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) From 6b36285053133d110ab09f20fdee15ca99f4735e Mon Sep 17 00:00:00 2001 From: quin lynch Date: Thu, 19 Aug 2021 02:43:49 -0300 Subject: [PATCH 23/23] Fix application command and thread starter messages being created as SocketSystemMessage --- src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs index 82c656486..1b62d14dd 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs @@ -122,7 +122,10 @@ namespace Discord.WebSocket } internal static SocketMessage Create(DiscordSocketClient discord, ClientState state, SocketUser author, ISocketMessageChannel channel, Model model) { - if (model.Type == MessageType.Default || model.Type == MessageType.Reply) + if (model.Type == MessageType.Default || + model.Type == MessageType.Reply || + model.Type == MessageType.ApplicationCommand || + model.Type == MessageType.ThreadStarterMessage) return SocketUserMessage.Create(discord, state, author, channel, model); else return SocketSystemMessage.Create(discord, state, author, channel, model);