From 121e3b4e77dfb2122ae4f3a3e475ecbc8b5a6104 Mon Sep 17 00:00:00 2001 From: SKProCH Date: Sun, 27 Jun 2021 16:28:05 +0300 Subject: [PATCH 1/7] Implemented new instant invite types --- .../Entities/Channels/INestedChannel.cs | 46 +++++++++++++++++- .../Entities/Invites/TargetUserType.cs | 6 ++- .../API/Rest/CreateChannelInviteParams.cs | 6 +++ src/Discord.Net.Rest/DiscordRestApiClient.cs | 6 +++ .../Entities/Channels/ChannelHelper.cs | 48 +++++++++++++++++++ .../Entities/Channels/RestTextChannel.cs | 8 +++- .../Entities/Channels/RestVoiceChannel.cs | 8 +++- .../Entities/Channels/SocketTextChannel.cs | 6 +++ .../Entities/Channels/SocketVoiceChannel.cs | 6 +++ .../MockedEntities/MockedTextChannel.cs | 4 ++ .../MockedEntities/MockedVoiceChannel.cs | 4 ++ 11 files changed, 143 insertions(+), 5 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs index 2c9503db1..d8072f94f 100644 --- a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs @@ -12,7 +12,7 @@ namespace Discord /// Gets the parent (category) ID of this channel in the guild's channel list. /// /// - /// A representing the snowflake identifier of the parent of this channel; + /// A representing the snowflake identifier of the parent of this channel; /// null if none is set. /// ulong? CategoryId { get; } @@ -56,6 +56,50 @@ namespace Discord /// metadata object containing information for the created invite. /// Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null); + + /// + /// Creates a new invite to this channel. + /// + /// + /// The following example creates a new invite to this channel; the invite lasts for 12 hours and can only + /// be used 3 times throughout its lifespan. + /// + /// await guildChannel.CreateInviteAsync(maxAge: 43200, maxUses: 3); + /// + /// + /// The id of the embedded application to open for this invite + /// The time (in seconds) until the invite expires. Set to null to never expire. + /// The max amount of times this invite may be used. Set to null to have unlimited uses. + /// If true, the user accepting this invite will be kicked from the guild after closing their client. + /// If true, don't try to reuse a similar invite (useful for creating many unique one time use invites). + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous invite creation operation. The task result contains an invite + /// metadata object containing information for the created invite. + /// + Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null); + + /// + /// Creates a new invite to this channel. + /// + /// + /// The following example creates a new invite to this channel; the invite lasts for 12 hours and can only + /// be used 3 times throughout its lifespan. + /// + /// await guildChannel.CreateInviteAsync(maxAge: 43200, maxUses: 3); + /// + /// + /// The id of the user whose stream to display for this invite + /// The time (in seconds) until the invite expires. Set to null to never expire. + /// The max amount of times this invite may be used. Set to null to have unlimited uses. + /// If true, the user accepting this invite will be kicked from the guild after closing their client. + /// If true, don't try to reuse a similar invite (useful for creating many unique one time use invites). + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous invite creation operation. The task result contains an invite + /// metadata object containing information for the created invite. + /// + Task CreateInviteToStreamAsync(IUser user, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null); /// /// Gets a collection of all invites to this channel. /// B diff --git a/src/Discord.Net.Core/Entities/Invites/TargetUserType.cs b/src/Discord.Net.Core/Entities/Invites/TargetUserType.cs index 74263b888..e1818d7a9 100644 --- a/src/Discord.Net.Core/Entities/Invites/TargetUserType.cs +++ b/src/Discord.Net.Core/Entities/Invites/TargetUserType.cs @@ -9,6 +9,10 @@ namespace Discord /// /// The invite is for a Go Live stream. /// - Stream = 1 + Stream = 1, + /// + /// The invite is for embedded application. + /// + EmbeddedApplication = 2 } } diff --git a/src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs b/src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs index db79bc314..06a47f1a8 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs @@ -14,5 +14,11 @@ namespace Discord.API.Rest public Optional IsTemporary { get; set; } [JsonProperty("unique")] public Optional IsUnique { get; set; } + [JsonProperty("target_type")] + public Optional TargetType { get; set; } + [JsonProperty("target_user_id")] + public Optional TargetUserId { get; set; } + [JsonProperty("target_application_id")] + public Optional TargetApplicationId { get; set; } } } diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index d7978db5c..70e7f9278 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -1079,6 +1079,12 @@ namespace Discord.API Preconditions.AtLeast(args.MaxUses, 0, nameof(args.MaxUses)); Preconditions.AtMost(args.MaxAge, 86400, nameof(args.MaxAge), "The maximum age of an invite must be less than or equal to a day (86400 seconds)."); + if (args.TargetType.IsSpecified) + { + Preconditions.NotEqual((int)args.TargetType.Value, (int)TargetUserType.Undefined, nameof(args.TargetType)); + if (args.TargetType.Value == TargetUserType.Stream) Preconditions.GreaterThan(args.TargetUserId, 0, nameof(args.TargetUserId)); + if (args.TargetType.Value == TargetUserType.EmbeddedApplication) Preconditions.GreaterThan(args.TargetApplicationId, 0, nameof(args.TargetUserId)); + } options = RequestOptions.CreateOrClone(options); var ids = new BucketIds(channelId: channelId); diff --git a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs index 22395ab3a..77f5e5b4c 100644 --- a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs +++ b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs @@ -120,6 +120,54 @@ namespace Discord.Rest return RestInviteMetadata.Create(client, null, channel, model); } + /// + /// may not be equal to zero. + /// -and- + /// and must be greater than zero. + /// -and- + /// must be lesser than 86400. + /// + public static async Task CreateInviteToStreamAsync(IGuildChannel channel, BaseDiscordClient client, + int? maxAge, int? maxUses, bool isTemporary, bool isUnique, IUser user, + RequestOptions options) + { + var args = new API.Rest.CreateChannelInviteParams + { + IsTemporary = isTemporary, + IsUnique = isUnique, + MaxAge = maxAge ?? 0, + MaxUses = maxUses ?? 0, + TargetType = TargetUserType.Stream, + TargetUserId = user.Id + }; + var model = await client.ApiClient.CreateChannelInviteAsync(channel.Id, args, options).ConfigureAwait(false); + return RestInviteMetadata.Create(client, null, channel, model); + } + + /// + /// may not be equal to zero. + /// -and- + /// and must be greater than zero. + /// -and- + /// must be lesser than 86400. + /// + public static async Task CreateInviteToApplicationAsync(IGuildChannel channel, BaseDiscordClient client, + int? maxAge, int? maxUses, bool isTemporary, bool isUnique, ulong applicationId, + RequestOptions options) + { + var args = new API.Rest.CreateChannelInviteParams + { + IsTemporary = isTemporary, + IsUnique = isUnique, + MaxAge = maxAge ?? 0, + MaxUses = maxUses ?? 0, + TargetType = TargetUserType.EmbeddedApplication, + TargetApplicationId = applicationId + }; + var model = await client.ApiClient.CreateChannelInviteAsync(channel.Id, args, options).ConfigureAwait(false); + return RestInviteMetadata.Create(client, null, channel, model); + } + //Messages public static async Task GetMessageAsync(IMessageChannel channel, BaseDiscordClient client, ulong id, RequestOptions options) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs index c6d0b0509..8597acd2f 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs @@ -17,7 +17,7 @@ namespace Discord.Rest /// public string Topic { get; private set; } /// - public virtual int SlowModeInterval { get; private set; } + public virtual int SlowModeInterval { get; private set; } /// public ulong? CategoryId { get; private set; } @@ -78,7 +78,7 @@ namespace Discord.Rest /// /// /// A paged collection containing a collection of guild users that can access this channel. Flattening the - /// paginated response into a collection of users with + /// paginated response into a collection of users with /// is required if you wish to access the users. /// public IAsyncEnumerable> GetUsersAsync(RequestOptions options = null) @@ -215,6 +215,10 @@ namespace Discord.Rest /// public async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); + public Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); + public Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); /// public async Task> GetInvitesAsync(RequestOptions options = null) => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); diff --git a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs index 3f3aa96c6..b551c7f8f 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs @@ -60,12 +60,18 @@ namespace Discord.Rest /// public Task SyncPermissionsAsync(RequestOptions options = null) => ChannelHelper.SyncPermissionsAsync(this, Discord, options); - + //Invites /// public async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); /// + public async Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); + /// + public async Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); + /// public async Task> GetInvitesAsync(RequestOptions options = null) => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs index 71a20c198..a9c1e8658 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs @@ -258,6 +258,12 @@ namespace Discord.WebSocket public async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); /// + public async Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); + /// + public async Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); + /// public async Task> GetInvitesAsync(RequestOptions options = null) => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs index bf4a63c9f..7dded5fa2 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs @@ -90,6 +90,12 @@ namespace Discord.WebSocket public async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); /// + public async Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); + /// + public async Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); + /// public async Task> GetInvitesAsync(RequestOptions options = null) => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs index 51aece5f2..633d52e4a 100644 --- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs +++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs @@ -46,6 +46,10 @@ namespace Discord { throw new NotImplementedException(); } + public Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); + public Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); public Task CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null) { diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs index eb617125d..7c3d00fdd 100644 --- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs +++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs @@ -47,6 +47,10 @@ namespace Discord { throw new NotImplementedException(); } + public Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); + public Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); public Task DeleteAsync(RequestOptions options = null) { From b76bf99dbe93714e03c953d16a59193f8782f240 Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Tue, 6 Jul 2021 14:07:32 -0300 Subject: [PATCH 2/7] Update README.md --- README.md | 85 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 981108982..f99f3ec4a 100644 --- a/README.md +++ b/README.md @@ -26,11 +26,7 @@ This branch is on pause and does not work currently, Once everything is stable w ### web/SlashCommandService webmilio's spin on the SlashCommandService branch, again the state of this is unknown. - -## Message Components -So, you want to use Message components? Well you're in luck! Below is a quick overview of how to use them - -#### Listening for button presses +## Listening for interactions ```cs // Subscribe to the InteractionCreated event client.InteractionCreated += Client_InteractionCreated; @@ -38,23 +34,86 @@ client.InteractionCreated += Client_InteractionCreated; ... private async Task Client_InteractionCreated(SocketInteraction arg) { - // If the type of the interaction is a message component - if(arg.Type == Discord.InteractionType.MessageComponent) + switch (arg.Type) // We want to check the type of this interaction { - // parse the args - var parsedArg = (SocketMessageComponent)arg; - // respond with the update message response type. This edits the original message if you have set AlwaysAcknowledgeInteractions to false. - await parsedArg.RespondAsync($"Clicked {parsedArg.Data.CustomId}!", type: InteractionResponseType.UpdateMessage); + //Slash commands + case InteractionType.ApplicationCommand: + await MySlashCommandHandler(arg); + break; + //Button clicks/selection dropdowns + case InteractionType.MessageComponent: + await MyMessageComponentHandler(arg); + break; + //Unused + case InteractionType.Ping: + break; + //Unknown/Unsupported + default: + Console.WriteLine("Unsupported interaction type: " + arg.Type); + break; } } ``` -#### Sending messages with buttons +### Handling button clicks and selection dropdowns +```cs +private async Task MyMessageComponentHandler(SocketInteraction arg) +{ + // Parse the arg + var parsedArg = (SocketMessageComponent) arg; + // Get the custom ID + var customId = parsedArg.Data.CustomId; + // Get the user + var user = (SocketGuildUser) arg.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); + + // You can also followup with a second message + await parsedArg.FollowupAsync($"Clicked {parsedArg.Data.CustomId}!", type: InteractionResponseType.ChannelMessageWithSource, 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(); +} +``` + +> Note: The example above assumes that the selection dropdown is expecting only 1 returned value, if you configured your dropdown for multiple values, you'll need to modify the code slightly. + +### Sending messages with buttons Theres a new field in all `SendMessageAsync` functions that takes in a `MessageComponent`, you can use it like so: ```cs -var builder = new ComponentBuilder().WithButton("Hello!", ButtonStyle.Primary, customId: "id_1"); +var builder = new ComponentBuilder().WithButton("Hello!", customId: "id_1", ButtonStyle.Primary, row: 0); await Context.Channel.SendMessageAsync("Test buttons!", component: builder.Build()); ``` +### Sending messages with selection dropdowns +Theres a new field in all `SendMessageAsync` functions that takes in a `MessageComponent`, you can use it like so: +```cs +var builder = new ComponentBuilder() + .WithSelectMenu(new SelectMenuBuilder() + .WithCustomId("id_2") + .WithLabel("Select menu!") + .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") + })); +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/blob/Interactions/docs/guides/commands/application-commands.md). 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) From a8a88d4419f760731efaf8f6b7e969c22436627f Mon Sep 17 00:00:00 2001 From: Playwo <38554182+Playwo@users.noreply.github.com> Date: Fri, 9 Jul 2021 15:52:31 +0200 Subject: [PATCH 3/7] Update README section about InteractivityAddon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f99f3ec4a..fb44c42e3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This repo is a custom fork of Discord.Net that introduces the newest features of discord for testing and experimenting. Nothing here is guaranteed to work but you are more than welcome to submit bugs in the issues tabs ## Known issues -Labs will not work with Playwo's [InteractivityAddon](https://github.com/Playwo/Discord.InteractivityAddon). The reason is that his package depends on the base discord.net lib, you can get around this by cloning his repo and building it with discord.net labs instead of discord.net. +Labs will not work with normal package of Playwo's [InteractivityAddon](https://www.nuget.org/packages/Discord.InteractivityAddon). The reason is that his package depends on the base discord.net lib. You can instead use the [InteractivityAddon.Labs](https://www.nuget.org/packages/Discord.InteractivityAddon.Labs) package which implements some of the features added in Discord.Net-Labs. ## How to use Setting up labs in your project is really simple, here's how to do it: From 8349cd7e1eb92e9a3baff68082c30a7b43e8e9b7 Mon Sep 17 00:00:00 2001 From: th0mk Date: Sat, 10 Jul 2021 16:40:52 +0200 Subject: [PATCH 4/7] fix: Change embed description max length to 4096 (#1886) * Update max embed description length (fixes #1881) * Update unit tests for new embed builder length --- src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs | 2 +- test/Discord.Net.Tests.Unit/EmbedBuilderTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs b/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs index f1238ddcf..89aaf5fde 100644 --- a/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs +++ b/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs @@ -27,7 +27,7 @@ namespace Discord /// /// Returns the maximum length of description allowed by Discord. /// - public const int MaxDescriptionLength = 2048; + public const int MaxDescriptionLength = 4096; /// /// Returns the maximum length of total characters allowed by Discord. /// diff --git a/test/Discord.Net.Tests.Unit/EmbedBuilderTests.cs b/test/Discord.Net.Tests.Unit/EmbedBuilderTests.cs index 6cfdc83b2..da21afee1 100644 --- a/test/Discord.Net.Tests.Unit/EmbedBuilderTests.cs +++ b/test/Discord.Net.Tests.Unit/EmbedBuilderTests.cs @@ -126,7 +126,7 @@ namespace Discord { IEnumerable GetInvalid() { - yield return new string('a', 2049); + yield return new string('a', 4097); } foreach (var description in GetInvalid()) { @@ -149,7 +149,7 @@ namespace Discord { yield return string.Empty; yield return null; - yield return new string('a', 2048); + yield return new string('a', 4096); } foreach (var description in GetValid()) { From c5b4b645b8eeea9698453be0602ad07dba9dabf8 Mon Sep 17 00:00:00 2001 From: Wardog <49387986+wrdg@users.noreply.github.com> Date: Sat, 10 Jul 2021 09:42:45 -0500 Subject: [PATCH 5/7] feature: Add Name property to Teams (#1879) --- src/Discord.Net.Core/Entities/Teams/ITeam.cs | 4 ++++ src/Discord.Net.Rest/API/Common/Team.cs | 2 ++ src/Discord.Net.Rest/Entities/Teams/RestTeam.cs | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/Discord.Net.Core/Entities/Teams/ITeam.cs b/src/Discord.Net.Core/Entities/Teams/ITeam.cs index 5ef3e4253..b6e3d987b 100644 --- a/src/Discord.Net.Core/Entities/Teams/ITeam.cs +++ b/src/Discord.Net.Core/Entities/Teams/ITeam.cs @@ -20,6 +20,10 @@ namespace Discord /// IReadOnlyList TeamMembers { get; } /// + /// Gets the name of this team. + /// + string Name { get; } + /// /// Gets the user identifier that owns this team. /// ulong OwnerUserId { get; } diff --git a/src/Discord.Net.Rest/API/Common/Team.cs b/src/Discord.Net.Rest/API/Common/Team.cs index 4910f43f7..852368522 100644 --- a/src/Discord.Net.Rest/API/Common/Team.cs +++ b/src/Discord.Net.Rest/API/Common/Team.cs @@ -11,6 +11,8 @@ namespace Discord.API public ulong Id { get; set; } [JsonProperty("members")] public TeamMember[] TeamMembers { get; set; } + [JsonProperty("name")] + public string Name { get; set; } [JsonProperty("owner_user_id")] public ulong OwnerUserId { get; set; } } diff --git a/src/Discord.Net.Rest/Entities/Teams/RestTeam.cs b/src/Discord.Net.Rest/Entities/Teams/RestTeam.cs index 2343f8b5d..43c9417cc 100644 --- a/src/Discord.Net.Rest/Entities/Teams/RestTeam.cs +++ b/src/Discord.Net.Rest/Entities/Teams/RestTeam.cs @@ -12,6 +12,8 @@ namespace Discord.Rest /// public IReadOnlyList TeamMembers { get; private set; } /// + public string Name { get; private set; } + /// public ulong OwnerUserId { get; private set; } private string _iconId; @@ -30,6 +32,7 @@ namespace Discord.Rest { if (model.Icon.IsSpecified) _iconId = model.Icon.Value; + Name = model.Name; OwnerUserId = model.OwnerUserId; TeamMembers = model.TeamMembers.Select(x => new RestTeamMember(Discord, x)).ToImmutableArray(); } From c20086158572acf5fbc3c795769d12b39b127482 Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Sat, 10 Jul 2021 11:44:32 -0300 Subject: [PATCH 6/7] fix: Add default avatar to WithAuthor extension (#1890) Adds `?? user.GetDefaultAvatarUrl()` to the avatar icon field. --- src/Discord.Net.Core/Extensions/EmbedBuilderExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Discord.Net.Core/Extensions/EmbedBuilderExtensions.cs b/src/Discord.Net.Core/Extensions/EmbedBuilderExtensions.cs index a3b8ddd5b..c05df7cb7 100644 --- a/src/Discord.Net.Core/Extensions/EmbedBuilderExtensions.cs +++ b/src/Discord.Net.Core/Extensions/EmbedBuilderExtensions.cs @@ -27,7 +27,7 @@ namespace Discord /// Fills the embed author field with the provided user's full username and avatar URL. public static EmbedBuilder WithAuthor(this EmbedBuilder builder, IUser user) => - builder.WithAuthor($"{user.Username}#{user.Discriminator}", user.GetAvatarUrl()); + builder.WithAuthor($"{user.Username}#{user.Discriminator}", user.GetAvatarUrl() ?? user.GetDefaultAvatarUrl()); /// Converts a object to a . /// The embed type is not . From d2c1053dd070a6edb08de3d2243d2fbeff78bbcd Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Sun, 11 Jul 2021 16:57:25 -0300 Subject: [PATCH 7/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb44c42e3..f0d08a030 100644 --- a/README.md +++ b/README.md @@ -116,4 +116,4 @@ await Context.Channel.SendMessageAsync("Test selection!", component: builder.Bui > 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/blob/Interactions/docs/guides/commands/application-commands.md). 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). 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)