Browse Source

Merge branch 'release/3.x' of https://github.com/Discord-Net-Labs/Discord.Net-Labs into merger-labs

Update requested changes of obsolete and references to labs.

Added `Interaction` to `IMessage`
Fixed grammar
Fixed bugs relating to interactions.
pull/1923/head
quin lynch 3 years ago
parent
commit
097d284e53
100 changed files with 545 additions and 601 deletions
  1. +11
    -2
      docs/guides/interactions/application-commands/slash-commands/02-creating-slash-commands.md
  2. +8
    -1
      docs/guides/interactions/application-commands/slash-commands/03-responding-to-slash-commands.md
  3. +5
    -0
      docs/guides/interactions/application-commands/slash-commands/04-parameters.md
  4. +7
    -14
      docs/guides/interactions/application-commands/slash-commands/05-responding-ephemerally.md
  5. +5
    -0
      docs/guides/interactions/application-commands/slash-commands/06-subcommands.md
  6. +5
    -0
      docs/guides/interactions/application-commands/slash-commands/07-choice-slash-command.md
  7. +9
    -3
      docs/guides/interactions/application-commands/slash-commands/08-bulk-overwrite-of-global-slash-commands.md
  8. +7
    -8
      docs/guides/interactions/application-commands/slash-commands/README.md
  9. +10
    -0
      docs/guides/interactions/intro.md
  10. +19
    -1
      docs/guides/toc.yml
  11. +1
    -1
      samples/02_commands_framework/02_commands_framework.csproj
  12. +1
    -1
      samples/02_commands_framework/Program.cs
  13. +1
    -1
      samples/03_sharded_client/03_sharded_client.csproj
  14. +1
    -1
      samples/03_sharded_client/Services/CommandHandlingService.cs
  15. +1
    -1
      samples/idn/idn.csproj
  16. +2
    -1
      src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj
  17. +1
    -1
      src/Discord.Net.Commands/Attributes/AliasAttribute.cs
  18. +1
    -1
      src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs
  19. +1
    -1
      src/Discord.Net.Commands/CommandService.cs
  20. +1
    -1
      src/Discord.Net.Commands/ModuleBase.cs
  21. +1
    -1
      src/Discord.Net.Commands/RunMode.cs
  22. +10
    -0
      src/Discord.Net.Core/CDN.cs
  23. +4
    -0
      src/Discord.Net.Core/Entities/Activities/ActivityType.cs
  24. +12
    -0
      src/Discord.Net.Core/Entities/AuditLogs/ActionType.cs
  25. +0
    -3
      src/Discord.Net.Core/Entities/Channels/IStageChannel.cs
  26. +5
    -8
      src/Discord.Net.Core/Entities/Channels/IThreadChannel.cs
  27. +0
    -6
      src/Discord.Net.Core/Entities/Channels/StageInstanceProperties.cs
  28. +0
    -6
      src/Discord.Net.Core/Entities/Channels/StagePrivacyLevel.cs
  29. +3
    -9
      src/Discord.Net.Core/Entities/Channels/ThreadArchiveDuration.cs
  30. +1
    -7
      src/Discord.Net.Core/Entities/Channels/ThreadType.cs
  31. +5
    -5
      src/Discord.Net.Core/Entities/Guilds/IGuild.cs
  32. +12
    -14
      src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs
  33. +8
    -12
      src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionChoice.cs
  34. +2
    -8
      src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionType.cs
  35. +0
    -6
      src/Discord.Net.Core/Entities/Interactions/ApplicationCommandProperties.cs
  36. +0
    -6
      src/Discord.Net.Core/Entities/Interactions/ApplicationCommandTypes.cs
  37. +0
    -6
      src/Discord.Net.Core/Entities/Interactions/AutocompleteOption.cs
  38. +17
    -25
      src/Discord.Net.Core/Entities/Interactions/AutocompleteResult.cs
  39. +5
    -16
      src/Discord.Net.Core/Entities/Interactions/Context Menus/MessageCommandBuilder.cs
  40. +0
    -6
      src/Discord.Net.Core/Entities/Interactions/Context Menus/MessageCommandProperties.cs
  41. +4
    -15
      src/Discord.Net.Core/Entities/Interactions/Context Menus/UserCommandBuilder.cs
  42. +0
    -6
      src/Discord.Net.Core/Entities/Interactions/Context Menus/UserCommandProperties.cs
  43. +0
    -2
      src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs
  44. +0
    -4
      src/Discord.Net.Core/Entities/Interactions/IApplicationCommandInteractionData.cs
  45. +0
    -5
      src/Discord.Net.Core/Entities/Interactions/IApplicationCommandInteractionDataOption.cs
  46. +7
    -6
      src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOption.cs
  47. +0
    -7
      src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOptionChoice.cs
  48. +7
    -10
      src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs
  49. +1
    -7
      src/Discord.Net.Core/Entities/Interactions/IDiscordInteractionData.cs
  50. +1
    -17
      src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs
  51. +1
    -7
      src/Discord.Net.Core/Entities/Interactions/InteractionType.cs
  52. +3
    -9
      src/Discord.Net.Core/Entities/Interactions/Message Components/ActionRowComponent.cs
  53. +1
    -8
      src/Discord.Net.Core/Entities/Interactions/Message Components/ButtonComponent.cs
  54. +0
    -6
      src/Discord.Net.Core/Entities/Interactions/Message Components/ButtonStyle.cs
  55. +5
    -11
      src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentType.cs
  56. +0
    -6
      src/Discord.Net.Core/Entities/Interactions/Message Components/IMessageComponent.cs
  57. +0
    -4
      src/Discord.Net.Core/Entities/Interactions/Message Components/MessageComponent.cs
  58. +0
    -3
      src/Discord.Net.Core/Entities/Interactions/Message Components/SelectMenuComponent.cs
  59. +0
    -6
      src/Discord.Net.Core/Entities/Interactions/Message Components/SelectMenuOption.cs
  60. +97
    -86
      src/Discord.Net.Core/Entities/Interactions/Slash Commands/SlashCommandBuilder.cs
  61. +0
    -4
      src/Discord.Net.Core/Entities/Interactions/Slash Commands/SlashCommandProperties.cs
  62. +7
    -7
      src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs
  63. +7
    -0
      src/Discord.Net.Core/Entities/Messages/IAttachment.cs
  64. +16
    -1
      src/Discord.Net.Core/Entities/Messages/IMessage.cs
  65. +34
    -0
      src/Discord.Net.Core/Entities/Messages/IMessageInteraction.cs
  66. +45
    -0
      src/Discord.Net.Core/Entities/Messages/MessageInteraction.cs
  67. +10
    -6
      src/Discord.Net.Core/Entities/Messages/MessageType.cs
  68. +16
    -6
      src/Discord.Net.Core/Entities/Messages/StickerFormatType.cs
  69. +4
    -13
      src/Discord.Net.Core/Entities/Messages/TimestampTag.cs
  70. +0
    -6
      src/Discord.Net.Core/Entities/Messages/TimestampTagStyle.cs
  71. +1
    -7
      src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissionTarget.cs
  72. +0
    -17
      src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs
  73. +2
    -2
      src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs
  74. +0
    -4
      src/Discord.Net.Core/Entities/Permissions/GuildApplicationCommandPermissions.cs
  75. +0
    -15
      src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs
  76. +1
    -1
      src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs
  77. +1
    -1
      src/Discord.Net.Core/Entities/Permissions/OverwritePermissions.cs
  78. +15
    -0
      src/Discord.Net.Core/Entities/Roles/IRole.cs
  79. +1
    -4
      src/Discord.Net.Core/Entities/Stickers/ICustomSticker.cs
  80. +2
    -4
      src/Discord.Net.Core/Entities/Stickers/ISticker.cs
  81. +0
    -6
      src/Discord.Net.Core/Entities/Stickers/IStickerItem.cs
  82. +1
    -5
      src/Discord.Net.Core/Entities/Stickers/StickerPack.cs
  83. +0
    -4
      src/Discord.Net.Core/Entities/Stickers/StickerProperties.cs
  84. +2
    -8
      src/Discord.Net.Core/Entities/Stickers/StickerType.cs
  85. +2
    -2
      src/Discord.Net.Core/Extensions/MessageExtensions.cs
  86. +14
    -1
      src/Discord.Net.Core/Format.cs
  87. +0
    -4
      src/Discord.Net.Core/Net/ApplicationCommandException.cs
  88. +2
    -2
      src/Discord.Net.Core/RequestOptions.cs
  89. +25
    -5
      src/Discord.Net.Core/Utils/UrlValidation.cs
  90. +0
    -1
      src/Discord.Net.Examples/Core/Entities/Channels/IMessageChannel.Examples.cs
  91. +1
    -1
      src/Discord.Net.Examples/Discord.Net.Examples.csproj
  92. +2
    -1
      src/Discord.Net.Providers.WS4Net/Discord.Net.Providers.WS4Net.csproj
  93. +1
    -6
      src/Discord.Net.Rest/API/Common/ActionRowComponent.cs
  94. +0
    -5
      src/Discord.Net.Rest/API/Common/ApplicationCommand.cs
  95. +0
    -2
      src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionData.cs
  96. +0
    -1
      src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionDataOption.cs
  97. +22
    -31
      src/Discord.Net.Rest/API/Common/ApplicationCommandOption.cs
  98. +0
    -5
      src/Discord.Net.Rest/API/Common/ApplicationCommandOptionChoice.cs
  99. +0
    -5
      src/Discord.Net.Rest/API/Common/ApplicationCommandPermissions.cs
  100. +2
    -0
      src/Discord.Net.Rest/API/Common/Attachment.cs

+ 11
- 2
docs/guides/interactions/application-commands/slash-commands/02-creating-slash-commands.md View File

@@ -1,3 +1,8 @@
---
uid: Guides.SlashCommands.Creating
title: Creating Slash Commands
---

# Creating your first slash commands. # Creating your first slash commands.


There are two kinds of Slash Commands: global commands and guild commands. There are two kinds of Slash Commands: global commands and guild commands.
@@ -35,7 +40,10 @@ The slash command builder will help you create slash commands. The builder has t
| AddOption | Function | Adds an option to the current slash command. | | AddOption | Function | Adds an option to the current slash command. |
| Build | Function | Builds the builder into a `SlashCommandCreationProperties` class used to make slash commands | | Build | Function | Builds the builder into a `SlashCommandCreationProperties` class used to make slash commands |


**Note**: Slash command names must be all lowercase!
> [!NOTE]
> Slash command names must be all lowercase!

## Creating a Slash Command


Let's use the slash command builder to make a global and guild command. Let's use the slash command builder to make a global and guild command.


@@ -84,4 +92,5 @@ public async Task Client_Ready()


``` ```


**Note**: Slash commands only need to be created once. They do _not_ have to be 'created' on every startup or connection. The example simple shows creating them in the ready event as it's simpler than creating normal bot commands to register slash commands.
> [!NOTE]
> Slash commands only need to be created once. They do _not_ have to be 'created' on every startup or connection. The example simple shows creating them in the ready event as it's simpler than creating normal bot commands to register slash commands.

+ 8
- 1
docs/guides/interactions/application-commands/slash-commands/03-responding-to-slash-commands.md View File

@@ -1,3 +1,8 @@
---
uid: Guides.SlashCommands.Receiving
title: Receiving and Responding to Slash Commands
---

# Responding to interactions. # Responding to interactions.


Interactions are the base thing sent over by Discord. Slash commands are one of the interaction types. In order to receive a slash command we have to listen to the `InteractionCreated` event. Let's add this to our code. Interactions are the base thing sent over by Discord. Slash commands are one of the interaction types. In order to receive a slash command we have to listen to the `InteractionCreated` event. Let's add this to our code.
@@ -45,6 +50,8 @@ Let's try this out!


Let's go over the response types quickly, as you would only change them for style points :P Let's go over the response types quickly, as you would only change them for style points :P


> After receiving an interaction, you must respond to acknowledge it. You can choose to respond with a message immediately using `RespondAsync()` or you can choose to send a deferred response with `DeferAsync()`. If choosing a deferred response, the user will see a loading state for the interaction, and you'll have up to 15 minutes to edit the original deferred response using `ModifyOriginalResponseAsync()`. You can read more about response types [here](https://discord.com/developers/docs/interactions/slash-commands#interaction-response)
> [!NOTE]
> After receiving an interaction, you must respond to acknowledge it. You can choose to respond with a message immediately using `RespondAsync()` or you can choose to send a deferred response with `DeferAsync()`.
> If choosing a deferred response, the user will see a loading state for the interaction, and you'll have up to 15 minutes to edit the original deferred response using `ModifyOriginalResponseAsync()`. You can read more about response types [here](https://discord.com/developers/docs/interactions/slash-commands#interaction-response)


This seems to be working! Next, we will look at parameters for slash commands. This seems to be working! Next, we will look at parameters for slash commands.

+ 5
- 0
docs/guides/interactions/application-commands/slash-commands/04-parameters.md View File

@@ -1,3 +1,8 @@
---
uid: Guides.SlashCommands.Parameters
title: Slash Command Parameters
---

# Slash command parameters # Slash command parameters


Slash commands can have a bunch of parameters, each their own type. Let's first go over the types of parameters we can have. Slash commands can have a bunch of parameters, each their own type. Let's first go over the types of parameters we can have.


+ 7
- 14
docs/guides/interactions/application-commands/slash-commands/05-responding-ephemerally.md View File

@@ -1,20 +1,13 @@
# Responding ephemerally

What is an ephemeral response? Basically, only the user who executed the command can see the result of it. In labs this is pretty simple to do.

First, we need to talk about `AlwaysAcknowledgeInteractions` in the discord config. `AlwaysAcknowledgeInteractions` will always acknowledge the message non-ephemerally, meaning any follow-up messages or responses will also be non-ephemeral. If you set `AlwaysAcknowledgeInteractions` to false, you can acknowledge interactions yourself with the ephemeral field set to your discretion.
---
uid: Guides.SlashCommands.Ephemeral
title: Ephemeral Responses
---


**Note**: You don't have to run arg.AcknowledgeAsync() to capture the interaction, you can use arg.RespondAsync with a message to capture it, this also follows the ephemeral rule.
# Responding ephemerally


Let's start by changing our client config.
What is an ephemeral response? Basically, only the user who executed the command can see the result of it, this is pretty simple to implement.


```cs
client = new DiscordSocketClient(new DiscordSocketConfig()
{
// Add this!
AlwaysAcknowledgeInteractions = false,
});
```
**Note**: You don't have to run arg.DeferAsync() to capture the interaction, you can use arg.RespondAsync() with a message to capture it, this also follows the ephemeral rule.


When responding with either `FollowupAsync` or `RespondAsync` you can pass in an `ephemeral` property. When setting it to true it will respond ephemerally, false and it will respond non-ephemerally. When responding with either `FollowupAsync` or `RespondAsync` you can pass in an `ephemeral` property. When setting it to true it will respond ephemerally, false and it will respond non-ephemerally.




+ 5
- 0
docs/guides/interactions/application-commands/slash-commands/06-subcommands.md View File

@@ -1,3 +1,8 @@
---
uid: Guides.SlashCommands.SubCommand
title: Sub Commands
---

# Subcommands # Subcommands


Subcommands allow you to have multiple commands available in a single command. They can be useful for representing sub options for a command. For example: A settings command. Let's first look at some limitations with subcommands set by discord. Subcommands allow you to have multiple commands available in a single command. They can be useful for representing sub options for a command. For example: A settings command. Let's first look at some limitations with subcommands set by discord.


+ 5
- 0
docs/guides/interactions/application-commands/slash-commands/07-choice-slash-command.md View File

@@ -1,3 +1,8 @@
---
uid: Guides.SlashCommands.Choices
title: Slash Command Choices
---

# Slash Command Choices. # Slash Command Choices.


With slash command options you can add choices, making the user select between some set values. Lets create a command that asks how much they like our bot! With slash command options you can add choices, making the user select between some set values. Lets create a command that asks how much they like our bot!


+ 9
- 3
docs/guides/interactions/application-commands/slash-commands/08-bulk-overwrite-of-global-slash-commands.md View File

@@ -1,4 +1,10 @@
---
uid: Guides.SlashCommands.BulkOverwrite
title: Slash Command Bulk Overwrites
---

If you have too many global commands then you might want to consider using the bulk overwrite function. If you have too many global commands then you might want to consider using the bulk overwrite function.

```cs ```cs
public async Task Client_Ready() { public async Task Client_Ready() {
List<ApplicationCommandProperties> applicationCommandProperties = new(); List<ApplicationCommandProperties> applicationCommandProperties = new();
@@ -8,7 +14,7 @@ public async Task Client_Ready() {
globalCommandHelp.WithName("help"); globalCommandHelp.WithName("help");
globalCommandHelp.WithDescription("Shows information about the bot."); globalCommandHelp.WithDescription("Shows information about the bot.");
applicationCommandProperties.Add(globalCommandHelp.Build()); applicationCommandProperties.Add(globalCommandHelp.Build());
// Slash command with name as its parameter. // Slash command with name as its parameter.
SlashCommandOptionBuilder slashCommandOptionBuilder = new(); SlashCommandOptionBuilder slashCommandOptionBuilder = new();
slashCommandOptionBuilder.WithName("name"); slashCommandOptionBuilder.WithName("name");
@@ -16,11 +22,11 @@ public async Task Client_Ready() {
slashCommandOptionBuilder.WithDescription("Add a family"); slashCommandOptionBuilder.WithDescription("Add a family");
slashCommandOptionBuilder.WithRequired(true); // Only add this if you want it to be required slashCommandOptionBuilder.WithRequired(true); // Only add this if you want it to be required


SlashCommandBuilder globalCommandAddFamily = new SlashCommandBuilder();
SlashCommandBuilder globalCommandAddFamily = new SlashCommandBuilder();
globalCommandAddFamily.WithName("add-family"); globalCommandAddFamily.WithName("add-family");
globalCommandAddFamily.WithDescription("Add a family"); globalCommandAddFamily.WithDescription("Add a family");
applicationCommandProperties.Add(globalCommandAddFamily.Build()); applicationCommandProperties.Add(globalCommandAddFamily.Build());
await _client.BulkOverwriteGlobalApplicationCommandsAsync(applicationCommandProperties.ToArray()); await _client.BulkOverwriteGlobalApplicationCommandsAsync(applicationCommandProperties.ToArray());
} catch (ApplicationCommandException exception) { } catch (ApplicationCommandException exception) {
var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented); var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented);


+ 7
- 8
docs/guides/interactions/application-commands/slash-commands/README.md View File

@@ -2,11 +2,10 @@


Here you can find some guides on how to use slash commands. Here you can find some guides on how to use slash commands.


1. [Getting started](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/01-getting-started.md)
2. [Creating a slash command](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/02-creating-slash-commands.md)
3. [Responding to slash commands](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/03-responding-to-slash-commands.md)
4. [Parameters in slash commands](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/04-parameters.md)
5. [Responding ephemerally](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/05-responding-ephemerally.md)
6. [Subcommands](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/06-subcommands.md)
7. [Choices](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/Interactions/docs/guides/slash-commands/07-choice-slash-command.md)
7. [Bulk overwrite of global slash commands](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/release/3.x/docs/guides/interactions/application-commands/slash-commands/08-bulk-overwrite-of-global-slash-commands.md)
1. [Creating a slash command](https://github.com/discord-net/Discord.Net/blob/dev/docs/guides/interactions/application-commands/slash-commands/02-creating-slash-commands.md)
2. [Responding to slash commands](https://github.com/discord-net/Discord.Net/blob/dev/docs/guides/interactions/application-commands/slash-commands/03-responding-to-slash-commands.md)
3. [Parameters in slash commands](https://github.com/discord-net/Discord.Net/blob/dev/docs/guides/interactions/application-commands/slash-commands/04-parameters.md)
4. [Responding ephemerally](https://github.com/discord-net/Discord.Net/blob/dev/docs/guides/interactions/application-commands/slash-commands/05-responding-ephemerally.md)
5. [Subcommands](https://github.com/discord-net/Discord.Net/blob/dev/docs/guides/interactions/application-commands/slash-commands/06-subcommands.md)
6. [Choices](https://github.com/discord-net/Discord.Net/blob/dev/docs/guides/interactions/application-commands/slash-commands/07-choice-slash-command.md)
7. [Bulk overwrite of global slash commands](https://github.com/discord-net/Discord.Net/blob/dev/docs/guides/interactions/application-commands/slash-commands/08-bulk-overwrite-of-global-slash-commands.md)

+ 10
- 0
docs/guides/interactions/intro.md View File

@@ -0,0 +1,10 @@
---
uid: Guides.Interactions.Intro
title: Introduction to Interactions
---

# Interactions

Placeholder text does the brrr.

Links to different sections of guides: msg comp / slash commands.

+ 19
- 1
docs/guides/toc.yml View File

@@ -35,9 +35,27 @@
topicUid: Guides.Commands.DI topicUid: Guides.Commands.DI
- name: Post-execution Handling - name: Post-execution Handling
topicUid: Guides.Commands.PostExecution topicUid: Guides.Commands.PostExecution
- name: Working with Interactions
items:
- name: Introduction
topicUid: Guides.Interactions.Intro
- name: Creating slash commands
topicUid: Guides.SlashCommands.Creating
- name: Receiving and responding to slash commands
topicUid: Guides.SlashCommands.Receiving
- name: Slash command parameters
topicUid: Guides.SlashCommands.Parameters
- name: Ephemeral responses
topicUid: Guides.SlashCommands.Ephemeral
- name: Sub commands
topicUid: Guides.SlashCommands.SubCommand
- name: Slash command choices
topicUid: Guides.SlashCommands.Choices
- name: Slash ommands Bulk Overwrites
topicUid: Guides.SlashCommands.BulkOverwrite
- name: Emoji - name: Emoji
topicUid: Guides.Emoji topicUid: Guides.Emoji
- name: Voice - name: Voice
topicUid: Guides.Voice.SendingVoice topicUid: Guides.Voice.SendingVoice
- name: Deployment - name: Deployment
topicUid: Guides.Deployment
topicUid: Guides.Deployment

+ 1
- 1
samples/02_commands_framework/02_commands_framework.csproj View File

@@ -6,7 +6,7 @@
</PropertyGroup> </PropertyGroup>


<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.2" />
</ItemGroup> </ItemGroup>


<ItemGroup> <ItemGroup>


+ 1
- 1
samples/02_commands_framework/Program.cs View File

@@ -39,7 +39,7 @@ namespace _02_commands_framework
services.GetRequiredService<CommandService>().Log += LogAsync; services.GetRequiredService<CommandService>().Log += LogAsync;


// Tokens should be considered secret data and never hard-coded. // Tokens should be considered secret data and never hard-coded.
// We can read from the environment variable to avoid hardcoding.
// We can read from the environment variable to avoid hard coding.
await client.LoginAsync(TokenType.Bot, Environment.GetEnvironmentVariable("token")); await client.LoginAsync(TokenType.Bot, Environment.GetEnvironmentVariable("token"));
await client.StartAsync(); await client.StartAsync();




+ 1
- 1
samples/03_sharded_client/03_sharded_client.csproj View File

@@ -7,7 +7,7 @@
</PropertyGroup> </PropertyGroup>


<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.2" />
</ItemGroup> </ItemGroup>


<ItemGroup> <ItemGroup>


+ 1
- 1
samples/03_sharded_client/Services/CommandHandlingService.cs View File

@@ -54,7 +54,7 @@ namespace _03_sharded_client.Services
if (!command.IsSpecified) if (!command.IsSpecified)
return; return;


// the command was succesful, we don't care about this result, unless we want to log that a command succeeded.
// the command was successful, we don't care about this result, unless we want to log that a command succeeded.
if (result.IsSuccess) if (result.IsSuccess)
return; return;




+ 1
- 1
samples/idn/idn.csproj View File

@@ -6,7 +6,7 @@
</PropertyGroup> </PropertyGroup>


<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.5.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.11.0" />
</ItemGroup> </ItemGroup>


<ItemGroup> <ItemGroup>


+ 2
- 1
src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj View File

@@ -5,12 +5,13 @@
<RootNamespace>Discord.Analyzers</RootNamespace> <RootNamespace>Discord.Analyzers</RootNamespace>
<Description>A Discord.Net extension adding support for design-time analysis of the API usage.</Description> <Description>A Discord.Net extension adding support for design-time analysis of the API usage.</Description>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks> <TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<PackageId>Discord.Net.Labs.Analyzers</PackageId>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
<DocumentationFile>..\Discord.Net.Analyzers\Discord.Net.Analyzers.xml</DocumentationFile> <DocumentationFile>..\Discord.Net.Analyzers\Discord.Net.Analyzers.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.3.1" />
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.11.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Discord.Net.Commands\Discord.Net.Commands.csproj" /> <ProjectReference Include="..\Discord.Net.Commands\Discord.Net.Commands.csproj" />


+ 1
- 1
src/Discord.Net.Commands/Attributes/AliasAttribute.cs View File

@@ -16,7 +16,7 @@ namespace Discord.Commands
/// <code language="cs"> /// <code language="cs">
/// [Command("stats")] /// [Command("stats")]
/// [Alias("stat", "info")] /// [Alias("stat", "info")]
/// public async Task GetStatsAsync(IUser user)
/// public <see langword="async"/> Task GetStatsAsync(IUser user)
/// { /// {
/// // ...pull stats /// // ...pull stats
/// } /// }


+ 1
- 1
src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs View File

@@ -291,7 +291,7 @@ namespace Discord.Commands
return reader; return reader;
} }


//We dont have a cached type reader, create one
//We don't have a cached type reader, create one
reader = ReflectionUtils.CreateObject<TypeReader>(typeReaderType.GetTypeInfo(), service, services); reader = ReflectionUtils.CreateObject<TypeReader>(typeReaderType.GetTypeInfo(), service, services);
service.AddTypeReader(paramType, reader, false); service.AddTypeReader(paramType, reader, false);




+ 1
- 1
src/Discord.Net.Commands/CommandService.cs View File

@@ -602,7 +602,7 @@ namespace Discord.Commands
//If we get this far, at least one parse was successful. Execute the most likely overload. //If we get this far, at least one parse was successful. Execute the most likely overload.
var chosenOverload = successfulParses[0]; var chosenOverload = successfulParses[0];
var result = await chosenOverload.Key.ExecuteAsync(context, chosenOverload.Value, services).ConfigureAwait(false); var result = await chosenOverload.Key.ExecuteAsync(context, chosenOverload.Value, services).ConfigureAwait(false);
if (!result.IsSuccess && !(result is RuntimeResult || result is ExecuteResult)) // succesful results raise the event in CommandInfo#ExecuteInternalAsync (have to raise it there b/c deffered execution)
if (!result.IsSuccess && !(result is RuntimeResult || result is ExecuteResult)) // successful results raise the event in CommandInfo#ExecuteInternalAsync (have to raise it there b/c deferred execution)
await _commandExecutedEvent.InvokeAsync(chosenOverload.Key.Command, context, result); await _commandExecutedEvent.InvokeAsync(chosenOverload.Key.Command, context, result);
return result; return result;
} }


+ 1
- 1
src/Discord.Net.Commands/ModuleBase.cs View File

@@ -36,7 +36,7 @@ namespace Discord.Commands
/// Specifies if notifications are sent for mentioned users and roles in the <paramref name="message"/>. /// Specifies if notifications are sent for mentioned users and roles in the <paramref name="message"/>.
/// If <c>null</c>, all mentioned roles and users will be notified. /// If <c>null</c>, all mentioned roles and users will be notified.
/// </param> /// </param>
/// <param name="options">The request options for this async request.</param>
/// <param name="options">The request options for this <see langword="async"/> request.</param>
/// <param name="messageReference">The message references to be included. Used to reply to specific messages.</param> /// <param name="messageReference">The message references to be included. Used to reply to specific messages.</param>
/// <param name="component">The message components to be included with this message. Used for interactions.</param> /// <param name="component">The message components to be included with this message. Used for interactions.</param>
/// <param name="stickers">A collection of stickers to send with the file.</param> /// <param name="stickers">A collection of stickers to send with the file.</param>


+ 1
- 1
src/Discord.Net.Commands/RunMode.cs View File

@@ -8,7 +8,7 @@ namespace Discord.Commands
public enum RunMode public enum RunMode
{ {
/// <summary> /// <summary>
/// The default behaviour set in <see cref="CommandServiceConfig"/>.
/// The default behavior set in <see cref="CommandServiceConfig"/>.
/// </summary> /// </summary>
Default, Default,
/// <summary> /// <summary>


+ 10
- 0
src/Discord.Net.Core/CDN.cs View File

@@ -86,6 +86,16 @@ namespace Discord
public static string GetGuildIconUrl(ulong guildId, string iconId) public static string GetGuildIconUrl(ulong guildId, string iconId)
=> iconId != null ? $"{DiscordConfig.CDNUrl}icons/{guildId}/{iconId}.jpg" : null; => iconId != null ? $"{DiscordConfig.CDNUrl}icons/{guildId}/{iconId}.jpg" : null;
/// <summary> /// <summary>
/// Returns a guild role's icon URL.
/// </summary>
/// <param name="roleId">The role identifier.</param>
/// <param name="roleHash">The icon hash.</param>
/// <returns>
/// A URL pointing to the guild role's icon.
/// </returns>
public static string GetGuildRoleIconUrl(ulong roleId, string roleHash)
=> roleHash != null ? $"{DiscordConfig.CDNUrl}role-icons/{roleId}/{roleHash}.png" : null;
/// <summary>
/// Returns a guild splash URL. /// Returns a guild splash URL.
/// </summary> /// </summary>
/// <param name="guildId">The guild snowflake identifier.</param> /// <param name="guildId">The guild snowflake identifier.</param>


+ 4
- 0
src/Discord.Net.Core/Entities/Activities/ActivityType.cs View File

@@ -25,5 +25,9 @@ namespace Discord
/// The user has set a custom status. /// The user has set a custom status.
/// </summary> /// </summary>
CustomStatus = 4, CustomStatus = 4,
/// <summary>
/// The user is competing in a game.
/// </summary>
Competing = 5,
} }
} }

+ 12
- 0
src/Discord.Net.Core/Entities/AuditLogs/ActionType.cs View File

@@ -180,5 +180,17 @@ namespace Discord
/// A sticker was deleted. /// A sticker was deleted.
/// </summary> /// </summary>
StickerDeleted = 92, StickerDeleted = 92,
/// <summary>
/// A thread was created.
/// </summary>
ThreadCreate = 110,
/// <summary>
/// A thread was updated.
/// </summary>
ThreadUpdate = 111,
/// <summary>
/// A thread was deleted.
/// </summary>
ThreadDelete = 112
} }
} }

+ 0
- 3
src/Discord.Net.Core/Entities/Channels/IStageChannel.cs View File

@@ -1,7 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;


namespace Discord namespace Discord


+ 5
- 8
src/Discord.Net.Core/Entities/Channels/IThreadChannel.cs View File

@@ -1,7 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;


namespace Discord namespace Discord
@@ -9,7 +6,7 @@ namespace Discord
/// <summary> /// <summary>
/// Represents a thread channel inside of a guild. /// Represents a thread channel inside of a guild.
/// </summary> /// </summary>
public interface IThreadChannel : ITextChannel, IGuildChannel
public interface IThreadChannel : ITextChannel
{ {
/// <summary> /// <summary>
/// Gets the type of the current thread channel. /// Gets the type of the current thread channel.
@@ -56,7 +53,7 @@ namespace Discord
/// </summary> /// </summary>
/// <param name="options">The options to be used when sending the request.</param> /// <param name="options">The options to be used when sending the request.</param>
/// <returns> /// <returns>
/// A task that represents the asynchronous join operation.
/// A task that represents the asynchronous join operation.
/// </returns> /// </returns>
Task JoinAsync(RequestOptions options = null); Task JoinAsync(RequestOptions options = null);


@@ -65,7 +62,7 @@ namespace Discord
/// </summary> /// </summary>
/// <param name="options">The options to be used when sending the request.</param> /// <param name="options">The options to be used when sending the request.</param>
/// <returns> /// <returns>
/// A task that represents the asynchronous leave operation.
/// A task that represents the asynchronous leave operation.
/// </returns> /// </returns>
Task LeaveAsync(RequestOptions options = null); Task LeaveAsync(RequestOptions options = null);


@@ -75,7 +72,7 @@ namespace Discord
/// <param name="user">The <see cref="IGuildUser"/> to add.</param> /// <param name="user">The <see cref="IGuildUser"/> to add.</param>
/// <param name="options">The options to be used when sending the request.</param> /// <param name="options">The options to be used when sending the request.</param>
/// <returns> /// <returns>
/// A task that represents the asynchronous operation of adding a member to a thread.
/// A task that represents the asynchronous operation of adding a member to a thread.
/// </returns> /// </returns>
Task AddUserAsync(IGuildUser user, RequestOptions options = null); Task AddUserAsync(IGuildUser user, RequestOptions options = null);


@@ -85,7 +82,7 @@ namespace Discord
/// <param name="user">The <see cref="IGuildUser"/> to remove from this thread.</param> /// <param name="user">The <see cref="IGuildUser"/> to remove from this thread.</param>
/// <param name="options">The options to be used when sending the request.</param> /// <param name="options">The options to be used when sending the request.</param>
/// <returns> /// <returns>
/// A task that represents the asynchronous operation of removing a user from this thread.
/// A task that represents the asynchronous operation of removing a user from this thread.
/// </returns> /// </returns>
Task RemoveUserAsync(IGuildUser user, RequestOptions options = null); Task RemoveUserAsync(IGuildUser user, RequestOptions options = null);
} }


+ 0
- 6
src/Discord.Net.Core/Entities/Channels/StageInstanceProperties.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>


+ 0
- 6
src/Discord.Net.Core/Entities/Channels/StagePrivacyLevel.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>


+ 3
- 9
src/Discord.Net.Core/Entities/Channels/ThreadArchiveDuration.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
@@ -24,7 +18,7 @@ namespace Discord
/// <summary> /// <summary>
/// Three days (4320 minutes). /// Three days (4320 minutes).
/// <remarks> /// <remarks>
/// This option is explicity avaliable to nitro users.
/// This option is explicitly available to nitro users.
/// </remarks> /// </remarks>
/// </summary> /// </summary>
ThreeDays = 4320, ThreeDays = 4320,
@@ -32,9 +26,9 @@ namespace Discord
/// <summary> /// <summary>
/// One week (10080 minutes). /// One week (10080 minutes).
/// <remarks> /// <remarks>
/// This option is explicity avaliable to nitro users.
/// This option is explicitly available to nitro users.
/// </remarks> /// </remarks>
/// </summary> /// </summary>
OneWeek = 10080,
OneWeek = 10080
} }
} }

+ 1
- 7
src/Discord.Net.Core/Entities/Channels/ThreadType.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
@@ -24,6 +18,6 @@ namespace Discord
/// <summary> /// <summary>
/// Represents a temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission /// Represents a temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission
/// </summary> /// </summary>
PrivateThread = 12,
PrivateThread = 12
} }
} }

+ 5
- 5
src/Discord.Net.Core/Entities/Guilds/IGuild.cs View File

@@ -609,12 +609,12 @@ namespace Discord
/// </returns> /// </returns>
Task<ITextChannel> GetRulesChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); Task<ITextChannel> GetRulesChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> /// <summary>
/// Gets the text channel channel where admins and moderators of Community guilds receive notices from Discord.
/// Gets the text channel where admins and moderators of Community guilds receive notices from Discord.
/// </summary> /// </summary>
/// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from cache.</param> /// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from cache.</param>
/// <param name="options">The options to be used when sending the request.</param> /// <param name="options">The options to be used when sending the request.</param>
/// <returns> /// <returns>
/// A task that represents the asynchronous get operation. The task result contains the text channel channel where
/// A task that represents the asynchronous get operation. The task result contains the text channel where
/// admins and moderators of Community guilds receive notices from Discord; <see langword="null" /> if none is set. /// admins and moderators of Community guilds receive notices from Discord; <see langword="null" /> if none is set.
/// </returns> /// </returns>
Task<ITextChannel> GetPublicUpdatesChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); Task<ITextChannel> GetPublicUpdatesChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
@@ -771,7 +771,7 @@ namespace Discord
/// <returns>A guild user associated with the specified <paramref name="userId" />; <see langword="null" /> if the user is already in the guild.</returns> /// <returns>A guild user associated with the specified <paramref name="userId" />; <see langword="null" /> if the user is already in the guild.</returns>
Task<IGuildUser> AddGuildUserAsync(ulong userId, string accessToken, Action<AddGuildUserProperties> func = null, RequestOptions options = null); Task<IGuildUser> AddGuildUserAsync(ulong userId, string accessToken, Action<AddGuildUserProperties> func = null, RequestOptions options = null);
/// <summary> /// <summary>
/// Disconnects the user from its current voice channel.
/// Disconnects the user from its current voice channel.
/// </summary> /// </summary>
/// <param name="user">The user to disconnect.</param> /// <param name="user">The user to disconnect.</param>
/// <returns>A task that represents the asynchronous operation for disconnecting a user.</returns> /// <returns>A task that represents the asynchronous operation for disconnecting a user.</returns>
@@ -834,7 +834,7 @@ namespace Discord
/// Downloads all users for this guild if the current list is incomplete. /// Downloads all users for this guild if the current list is incomplete.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This method downloads all users found within this guild throught the Gateway and caches them.
/// This method downloads all users found within this guild through the Gateway and caches them.
/// </remarks> /// </remarks>
/// <returns> /// <returns>
/// A task that represents the asynchronous download operation. /// A task that represents the asynchronous download operation.
@@ -1057,7 +1057,7 @@ namespace Discord
/// A task that represents the asynchronous get operation. The task result contains a read-only collection /// A task that represents the asynchronous get operation. The task result contains a read-only collection
/// of application commands found within the guild. /// of application commands found within the guild.
/// </returns> /// </returns>
Task<IReadOnlyCollection<IApplicationCommand>> GetApplicationCommandsAsync (RequestOptions options = null);
Task<IReadOnlyCollection<IApplicationCommand>> GetApplicationCommandsAsync(RequestOptions options = null);


/// <summary> /// <summary>
/// Gets an application command within this guild with the specified id. /// Gets an application command within this guild with the specified id.


+ 12
- 14
src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs View File

@@ -1,9 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {
@@ -24,13 +21,13 @@ namespace Discord
set set
{ {
if (value == null) if (value == null)
throw new ArgumentNullException($"{nameof(Name)} cannot be null!");
throw new ArgumentNullException(nameof(value), $"{nameof(Name)} cannot be null.");


if (value.Length > 32) if (value.Length > 32)
throw new ArgumentException($"{nameof(Name)} length must be less than or equal to 32");
throw new ArgumentOutOfRangeException(nameof(value), "Name length must be less than or equal to 32.");


if (!Regex.IsMatch(value, @"^[\w-]{1,32}$")) if (!Regex.IsMatch(value, @"^[\w-]{1,32}$"))
throw new ArgumentException($"{nameof(Name)} must match the regex ^[\\w-]{{1,32}}$");
throw new FormatException($"{nameof(value)} must match the regex ^[\\w-]{{1,32}}$");


_name = value; _name = value;
} }
@@ -42,14 +39,12 @@ namespace Discord
public string Description public string Description
{ {
get => _description; get => _description;
set
set => _description = value?.Length switch
{ {
if (value?.Length > 100)
throw new ArgumentException("Description length must be less than or equal to 100");
if (value?.Length < 1)
throw new ArgumentException("Description length must at least 1 character in length");
_description = value;
}
> 100 => throw new ArgumentOutOfRangeException(nameof(value), "Description length must be less than or equal to 100."),
0 => throw new ArgumentOutOfRangeException(nameof(value), "Description length must be at least 1."),
_ => value
};
} }


/// <summary> /// <summary>
@@ -81,6 +76,9 @@ namespace Discord
/// </summary> /// </summary>
public List<ApplicationCommandOptionProperties> Options { get; set; } public List<ApplicationCommandOptionProperties> Options { get; set; }


/// <summary>
/// Gets or sets the allowed channel types for this option.
/// </summary>
public List<ChannelType> ChannelTypes { get; set; }
} }
} }

+ 8
- 12
src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionChoice.cs View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {
@@ -19,20 +15,18 @@ namespace Discord
public string Name public string Name
{ {
get => _name; get => _name;
set
set => _name = value?.Length switch
{ {
if(value?.Length > 100)
throw new ArgumentException("Name length must be less than or equal to 100");
if (value?.Length < 1)
throw new ArgumentException("Name length must at least 1 character in length");
_name = value;
}
> 100 => throw new ArgumentOutOfRangeException(nameof(value), "Name length must be less than or equal to 100."),
0 => throw new ArgumentOutOfRangeException(nameof(value), "Name length must at least 1."),
_ => value
};
} }


/// <summary> /// <summary>
/// Gets or sets the value of this choice. /// Gets or sets the value of this choice.
/// <note type="warning"> /// <note type="warning">
/// Discord only accepts int and string as the input.
/// Discord only accepts int, string, and doubles as the input.
/// </note> /// </note>
/// </summary> /// </summary>
public object Value public object Value
@@ -40,6 +34,8 @@ namespace Discord
get => _value; get => _value;
set set
{ {
if (value != null && value is not int && value is not string && value is not double)
throw new ArgumentException("The value of a choice must be a string, int, or double!");
_value = value; _value = value;
} }
} }


+ 2
- 8
src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionType.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
@@ -37,7 +31,7 @@ namespace Discord
Boolean = 5, Boolean = 5,


/// <summary> /// <summary>
/// A <see cref="IGuildUser"/>.
/// A <see cref="IUser"/>.
/// </summary> /// </summary>
User = 6, User = 6,


@@ -55,7 +49,7 @@ namespace Discord
/// A <see cref="IUser"/> or <see cref="IRole"/>. /// A <see cref="IUser"/> or <see cref="IRole"/>.
/// </summary> /// </summary>
Mentionable = 9, Mentionable = 9,
/// <summary> /// <summary>
/// A <see cref="double"/>. /// A <see cref="double"/>.
/// </summary> /// </summary>


+ 0
- 6
src/Discord.Net.Core/Entities/Interactions/ApplicationCommandProperties.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>


+ 0
- 6
src/Discord.Net.Core/Entities/Interactions/ApplicationCommandTypes.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>


+ 0
- 6
src/Discord.Net.Core/Entities/Interactions/AutocompleteOption.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>


+ 17
- 25
src/Discord.Net.Core/Entities/Interactions/AutocompleteResult.cs View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {
@@ -11,8 +7,8 @@ namespace Discord
/// </summary> /// </summary>
public class AutocompleteResult public class AutocompleteResult
{ {
private object _value { get; set; }
private string _name { get; set; }
private object _value;
private string _name;


/// <summary> /// <summary>
/// Gets or sets the name of the result. /// Gets or sets the name of the result.
@@ -28,12 +24,13 @@ namespace Discord
set set
{ {
if (value == null) if (value == null)
throw new ArgumentException("Name cannot be null!");
if (value.Length > 100)
throw new ArgumentException("Name length must be less than or equal to 100 characters in length!");
if (value.Length < 1)
throw new ArgumentException("Name length must at least 1 character in length!");
_name = value;
throw new ArgumentNullException(nameof(value), $"{nameof(Name)} cannot be null.");
_name = value.Length switch
{
> 100 => throw new ArgumentOutOfRangeException(nameof(value), "Name length must be less than or equal to 100."),
0 => throw new ArgumentOutOfRangeException(nameof(value), "Name length must be at least 1."),
_ => value
};
} }
} }


@@ -48,20 +45,15 @@ namespace Discord
public object Value public object Value
{ {
get => _value; get => _value;
set
set => _value = value switch
{ {
if (value == null)
throw new ArgumentNullException("Value cannot be null");

_value = value switch
{
string str => str,
int integer => integer,
long lng => lng,
double number => number,
_ => throw new ArgumentException($"Type {value.GetType().Name} cannot be set as a value! Only string, int, and double allowed!"),
};
}
string str => str,
int integer => integer,
long lng => lng,
double number => number,
null => throw new ArgumentNullException(nameof(value), $"{nameof(Value)} cannot be null."),
_ => throw new ArgumentException($"Type {value.GetType().Name} cannot be set as a value! Only string, int, and double allowed!")
};
} }


/// <summary> /// <summary>


+ 5
- 16
src/Discord.Net.Core/Entities/Interactions/Context Menus/MessageCommandBuilder.cs View File

@@ -1,10 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
@@ -12,8 +5,8 @@ namespace Discord
/// </summary> /// </summary>
public class MessageCommandBuilder public class MessageCommandBuilder
{ {
/// <summary>
/// Returns the maximun length a commands name allowed by Discord
/// <summary>
/// Returns the maximum length a commands name allowed by Discord
/// </summary> /// </summary>
public const int MaxNameLength = 32; public const int MaxNameLength = 32;


@@ -22,10 +15,7 @@ namespace Discord
/// </summary> /// </summary>
public string Name public string Name
{ {
get
{
return _name;
}
get => _name;
set set
{ {
Preconditions.NotNullOrEmpty(value, nameof(Name)); Preconditions.NotNullOrEmpty(value, nameof(Name));
@@ -41,7 +31,7 @@ namespace Discord
/// </summary> /// </summary>
public bool IsDefaultPermission { get; set; } = true; public bool IsDefaultPermission { get; set; } = true;


private string _name { get; set; }
private string _name;


/// <summary> /// <summary>
/// Build the current builder into a <see cref="MessageCommandProperties"/> class. /// Build the current builder into a <see cref="MessageCommandProperties"/> class.
@@ -51,14 +41,13 @@ namespace Discord
/// </returns> /// </returns>
public MessageCommandProperties Build() public MessageCommandProperties Build()
{ {
MessageCommandProperties props = new MessageCommandProperties()
var props = new MessageCommandProperties
{ {
Name = Name, Name = Name,
IsDefaultPermission = IsDefaultPermission IsDefaultPermission = IsDefaultPermission
}; };


return props; return props;

} }


/// <summary> /// <summary>


+ 0
- 6
src/Discord.Net.Core/Entities/Interactions/Context Menus/MessageCommandProperties.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>


+ 4
- 15
src/Discord.Net.Core/Entities/Interactions/Context Menus/UserCommandBuilder.cs View File

@@ -1,10 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
@@ -13,7 +6,7 @@ namespace Discord
public class UserCommandBuilder public class UserCommandBuilder
{ {
/// <summary> /// <summary>
/// Returns the maximun length a commands name allowed by Discord
/// Returns the maximum length a commands name allowed by Discord.
/// </summary> /// </summary>
public const int MaxNameLength = 32; public const int MaxNameLength = 32;


@@ -22,10 +15,7 @@ namespace Discord
/// </summary> /// </summary>
public string Name public string Name
{ {
get
{
return _name;
}
get => _name;
set set
{ {
Preconditions.NotNullOrEmpty(value, nameof(Name)); Preconditions.NotNullOrEmpty(value, nameof(Name));
@@ -41,7 +31,7 @@ namespace Discord
/// </summary> /// </summary>
public bool IsDefaultPermission { get; set; } = true; public bool IsDefaultPermission { get; set; } = true;


private string _name { get; set; }
private string _name;


/// <summary> /// <summary>
/// Build the current builder into a <see cref="UserCommandProperties"/> class. /// Build the current builder into a <see cref="UserCommandProperties"/> class.
@@ -49,14 +39,13 @@ namespace Discord
/// <returns>A <see cref="UserCommandProperties"/> that can be used to create user commands.</returns> /// <returns>A <see cref="UserCommandProperties"/> that can be used to create user commands.</returns>
public UserCommandProperties Build() public UserCommandProperties Build()
{ {
UserCommandProperties props = new UserCommandProperties()
var props = new UserCommandProperties
{ {
Name = Name, Name = Name,
IsDefaultPermission = IsDefaultPermission IsDefaultPermission = IsDefaultPermission
}; };


return props; return props;

} }


/// <summary> /// <summary>


+ 0
- 6
src/Discord.Net.Core/Entities/Interactions/Context Menus/UserCommandProperties.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>


+ 0
- 2
src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs View File

@@ -1,7 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;


namespace Discord namespace Discord


+ 0
- 4
src/Discord.Net.Core/Entities/Interactions/IApplicationCommandInteractionData.cs View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {


+ 0
- 5
src/Discord.Net.Core/Entities/Interactions/IApplicationCommandInteractionDataOption.cs View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {
@@ -33,6 +29,5 @@ namespace Discord
/// Gets the nested options of this option. /// Gets the nested options of this option.
/// </summary> /// </summary>
IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options { get; } IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options { get; }

} }
} }

+ 7
- 6
src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOption.cs View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {
@@ -39,11 +35,16 @@ namespace Discord
/// <summary> /// <summary>
/// Gets a collection of choices for the user to pick from. /// Gets a collection of choices for the user to pick from.
/// </summary> /// </summary>
IReadOnlyCollection<IApplicationCommandOptionChoice>? Choices { get; }
IReadOnlyCollection<IApplicationCommandOptionChoice> Choices { get; }


/// <summary> /// <summary>
/// Gets the nested options of this option. /// Gets the nested options of this option.
/// </summary> /// </summary>
IReadOnlyCollection<IApplicationCommandOption>? Options { get; }
IReadOnlyCollection<IApplicationCommandOption> Options { get; }

/// <summary>
/// The allowed channel types for this option.
/// </summary>
IReadOnlyCollection<ChannelType> ChannelTypes { get; }
} }
} }

+ 0
- 7
src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOptionChoice.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
@@ -20,6 +14,5 @@ namespace Discord
/// Gets the value of the choice. /// Gets the value of the choice.
/// </summary> /// </summary>
object Value { get; } object Value { get; }

} }
} }

+ 7
- 10
src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs View File

@@ -1,7 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;


namespace Discord namespace Discord
@@ -51,7 +48,7 @@ namespace Discord
/// <param name="options">The request options for this response.</param> /// <param name="options">The request options for this response.</param>
/// <param name="component">A <see cref="MessageComponent"/> to be sent with this response.</param> /// <param name="component">A <see cref="MessageComponent"/> to be sent with this response.</param>
/// <param name="embed">A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored.</param> /// <param name="embed">A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored.</param>
Task RespondAsync (string text = null, Embed[] embeds = null, bool isTTS = false,
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); bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null);


/// <summary> /// <summary>
@@ -68,23 +65,23 @@ namespace Discord
/// <returns> /// <returns>
/// The sent message. /// The sent message.
/// </returns> /// </returns>
Task<IUserMessage> FollowupAsync (string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false,
Task<IUserMessage> 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); AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null);


/// <summary> /// <summary>
/// Gets the original response for this interaction. /// Gets the original response for this interaction.
/// </summary> /// </summary>
/// <param name="options">The request options for this async request.</param>
/// <param name="options">The request options for this <see langword="async"/> request.</param>
/// <returns>A <see cref="IUserMessage"/> that represents the initial response.</returns> /// <returns>A <see cref="IUserMessage"/> that represents the initial response.</returns>
Task<IUserMessage> GetOriginalResponseAsync (RequestOptions options = null);
Task<IUserMessage> GetOriginalResponseAsync(RequestOptions options = null);


/// <summary> /// <summary>
/// Edits original response for this interaction. /// Edits original response for this interaction.
/// </summary> /// </summary>
/// <param name="func">A delegate containing the properties to modify the message with.</param> /// <param name="func">A delegate containing the properties to modify the message with.</param>
/// <param name="options">The request options for this async request.</param>
/// <param name="options">The request options for this <see langword="async"/> request.</param>
/// <returns>A <see cref="IUserMessage"/> that represents the initial response.</returns> /// <returns>A <see cref="IUserMessage"/> that represents the initial response.</returns>
Task<IUserMessage> ModifyOriginalResponseAsync (Action<MessageProperties> func, RequestOptions options = null);
Task<IUserMessage> ModifyOriginalResponseAsync(Action<MessageProperties> func, RequestOptions options = null);


/// <summary> /// <summary>
/// Acknowledges this interaction. /// Acknowledges this interaction.
@@ -92,6 +89,6 @@ namespace Discord
/// <returns> /// <returns>
/// A task that represents the asynchronous operation of acknowledging the interaction. /// A task that represents the asynchronous operation of acknowledging the interaction.
/// </returns> /// </returns>
Task DeferAsync (bool ephemeral = false, RequestOptions options = null);
Task DeferAsync(bool ephemeral = false, RequestOptions options = null);
} }
} }

+ 1
- 7
src/Discord.Net.Core/Entities/Interactions/IDiscordInteractionData.cs View File

@@ -1,13 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
/// Represents an interface used to specify classes that they are a vaild dataype of a <see cref="IDiscordInteraction"/> class.
/// Represents an interface used to specify classes that they are a valid data type of a <see cref="IDiscordInteraction"/> class.
/// </summary> /// </summary>
public interface IDiscordInteractionData { } public interface IDiscordInteractionData { }
} }

+ 1
- 17
src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {
@@ -13,7 +9,7 @@ namespace Discord
/// After receiving an interaction, you must respond to acknowledge it. You can choose to respond with a message immediately using <see cref="ChannelMessageWithSource"/> /// After receiving an interaction, you must respond to acknowledge it. You can choose to respond with a message immediately using <see cref="ChannelMessageWithSource"/>
/// or you can choose to send a deferred response with <see cref="DeferredChannelMessageWithSource"/>. If choosing a deferred response, the user will see a loading state for the interaction, /// or you can choose to send a deferred response with <see cref="DeferredChannelMessageWithSource"/>. If choosing a deferred response, the user will see a loading state for the interaction,
/// and you'll have up to 15 minutes to edit the original deferred response using Edit Original Interaction Response. /// and you'll have up to 15 minutes to edit the original deferred response using Edit Original Interaction Response.
/// You can read more about Response types <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-response">Here</see>
/// You can read more about Response types <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-response">Here</see>.
/// </remarks> /// </remarks>
public enum InteractionResponseType : byte public enum InteractionResponseType : byte
{ {
@@ -22,18 +18,6 @@ namespace Discord
/// </summary> /// </summary>
Pong = 1, Pong = 1,


/// <summary>
/// ACK a command without sending a message, eating the user's input.
/// </summary>
[Obsolete("This response type has been depricated by discord. Either use ChannelMessageWithSource or DeferredChannelMessageWithSource", true)]
Acknowledge = 2,

/// <summary>
/// Respond with a message, showing the user's input.
/// </summary>
[Obsolete("This response type has been depricated by discord. Either use ChannelMessageWithSource or DeferredChannelMessageWithSource", true)]
ChannelMessage = 3,

/// <summary> /// <summary>
/// Respond to an interaction with a message. /// Respond to an interaction with a message.
/// </summary> /// </summary>


+ 1
- 7
src/Discord.Net.Core/Entities/Interactions/InteractionType.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
@@ -29,6 +23,6 @@ namespace Discord
/// <summary> /// <summary>
/// An autocomplete request sent from discord. /// An autocomplete request sent from discord.
/// </summary> /// </summary>
ApplicationCommandAutocomplete = 4,
ApplicationCommandAutocomplete = 4
} }
} }

+ 3
- 9
src/Discord.Net.Core/Entities/Interactions/Message Components/ActionRowComponent.cs View File

@@ -1,28 +1,22 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
/// Represents a <see cref="IMessageComponent"/> Row for child components to live in.
/// Represents a <see cref="IMessageComponent"/> Row for child components to live in.
/// </summary> /// </summary>
public class ActionRowComponent : IMessageComponent public class ActionRowComponent : IMessageComponent
{ {
/// <inheritdoc/> /// <inheritdoc/>
public ComponentType Type { get; } = ComponentType.ActionRow;
public ComponentType Type => ComponentType.ActionRow;


/// <summary> /// <summary>
/// Gets the child components in this row. /// Gets the child components in this row.
/// </summary> /// </summary>
public IReadOnlyCollection<IMessageComponent> Components { get; internal set; } public IReadOnlyCollection<IMessageComponent> Components { get; internal set; }



internal ActionRowComponent() { } internal ActionRowComponent() { }

internal ActionRowComponent(List<IMessageComponent> components) internal ActionRowComponent(List<IMessageComponent> components)
{ {
Components = components; Components = components;


+ 1
- 8
src/Discord.Net.Core/Entities/Interactions/Message Components/ButtonComponent.cs View File

@@ -1,10 +1,3 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
@@ -13,7 +6,7 @@ namespace Discord
public class ButtonComponent : IMessageComponent public class ButtonComponent : IMessageComponent
{ {
/// <inheritdoc/> /// <inheritdoc/>
public ComponentType Type { get; } = ComponentType.Button;
public ComponentType Type => ComponentType.Button;


/// <summary> /// <summary>
/// Gets the <see cref="ButtonStyle"/> of this button, example buttons with each style can be found <see href="https://discord.com/assets/7bb017ce52cfd6575e21c058feb3883b.png">Here</see>. /// Gets the <see cref="ButtonStyle"/> of this button, example buttons with each style can be found <see href="https://discord.com/assets/7bb017ce52cfd6575e21c058feb3883b.png">Here</see>.


+ 0
- 6
src/Discord.Net.Core/Entities/Interactions/Message Components/ButtonStyle.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>


+ 5
- 11
src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentType.cs View File

@@ -1,29 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
/// Represents a type of a component
/// Represents a type of a component.
/// </summary> /// </summary>
public enum ComponentType public enum ComponentType
{ {
/// <summary> /// <summary>
/// A container for other components
/// A container for other components.
/// </summary> /// </summary>
ActionRow = 1, ActionRow = 1,


/// <summary> /// <summary>
/// A clickable button
/// A clickable button.
/// </summary> /// </summary>
Button = 2, Button = 2,


/// <summary> /// <summary>
/// A select menu for picking from choices
/// A select menu for picking from choices.
/// </summary> /// </summary>
SelectMenu = 3,
SelectMenu = 3
} }
} }

+ 0
- 6
src/Discord.Net.Core/Entities/Interactions/Message Components/IMessageComponent.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>


+ 0
- 4
src/Discord.Net.Core/Entities/Interactions/Message Components/MessageComponent.cs View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {


+ 0
- 3
src/Discord.Net.Core/Entities/Interactions/Message Components/SelectMenuComponent.cs View File

@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {


+ 0
- 6
src/Discord.Net.Core/Entities/Interactions/Message Components/SelectMenuOption.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>


+ 97
- 86
src/Discord.Net.Core/Entities/Interactions/Slash Commands/SlashCommandBuilder.cs View File

@@ -1,9 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {
@@ -12,15 +10,15 @@ namespace Discord
/// </summary> /// </summary>
public class SlashCommandBuilder public class SlashCommandBuilder
{ {
/// <summary>
/// Returns the maximun length a commands name allowed by Discord
/// <summary>
/// Returns the maximum length a commands name allowed by Discord
/// </summary> /// </summary>
public const int MaxNameLength = 32; public const int MaxNameLength = 32;
/// <summary>
/// Returns the maximum length of a commands description allowed by Discord.
/// <summary>
/// Returns the maximum length of a commands description allowed by Discord.
/// </summary> /// </summary>
public const int MaxDescriptionLength = 100; public const int MaxDescriptionLength = 100;
/// <summary>
/// <summary>
/// Returns the maximum count of command options allowed by Discord /// Returns the maximum count of command options allowed by Discord
/// </summary> /// </summary>
public const int MaxOptionsCount = 25; public const int MaxOptionsCount = 25;
@@ -30,20 +28,17 @@ namespace Discord
/// </summary> /// </summary>
public string Name public string Name
{ {
get
{
return _name;
}
get => _name;
set set
{ {
Preconditions.NotNullOrEmpty(value, nameof(Name));
Preconditions.AtLeast(value.Length, 1, nameof(Name));
Preconditions.AtMost(value.Length, MaxNameLength, nameof(Name));
Preconditions.NotNullOrEmpty(value, nameof(value));
Preconditions.AtLeast(value.Length, 1, nameof(value));
Preconditions.AtMost(value.Length, MaxNameLength, nameof(value));


// Discord updated the docs, this regex prevents special characters like @!$%(... etc, // Discord updated the docs, this regex prevents special characters like @!$%(... etc,
// https://discord.com/developers/docs/interactions/slash-commands#applicationcommand // https://discord.com/developers/docs/interactions/slash-commands#applicationcommand
if (!Regex.IsMatch(value, @"^[\w-]{1,32}$")) if (!Regex.IsMatch(value, @"^[\w-]{1,32}$"))
throw new ArgumentException("Command name cannot contain any special characters or whitespaces!");
throw new ArgumentException("Command name cannot contain any special characters or whitespaces!", nameof(value));


_name = value; _name = value;
} }
@@ -54,12 +49,10 @@ namespace Discord
/// </summary> /// </summary>
public string Description public string Description
{ {
get
{
return _description;
}
get => _description;
set set
{ {
Preconditions.NotNullOrEmpty(value, nameof(Description));
Preconditions.AtLeast(value.Length, 1, nameof(Description)); Preconditions.AtLeast(value.Length, 1, nameof(Description));
Preconditions.AtMost(value.Length, MaxDescriptionLength, nameof(Description)); Preconditions.AtMost(value.Length, MaxDescriptionLength, nameof(Description));


@@ -75,10 +68,7 @@ namespace Discord
get => _options; get => _options;
set set
{ {
if (value != null)
if (value.Count > MaxOptionsCount)
throw new ArgumentException(message: $"Option count must be less than or equal to {MaxOptionsCount}.", paramName: nameof(Options));

Preconditions.AtMost(value?.Count ?? 0, MaxOptionsCount, nameof(value));
_options = value; _options = value;
} }
} }
@@ -88,9 +78,9 @@ namespace Discord
/// </summary> /// </summary>
public bool IsDefaultPermission { get; set; } = true; public bool IsDefaultPermission { get; set; } = true;


private string _name { get; set; }
private string _description { get; set; }
private List<SlashCommandOptionBuilder> _options { get; set; }
private string _name;
private string _description;
private List<SlashCommandOptionBuilder> _options;


/// <summary> /// <summary>
/// Build the current builder into a <see cref="SlashCommandProperties"/> class. /// Build the current builder into a <see cref="SlashCommandProperties"/> class.
@@ -98,7 +88,7 @@ namespace Discord
/// <returns>A <see cref="SlashCommandProperties"/> that can be used to create slash commands.</returns> /// <returns>A <see cref="SlashCommandProperties"/> that can be used to create slash commands.</returns>
public SlashCommandProperties Build() public SlashCommandProperties Build()
{ {
SlashCommandProperties props = new SlashCommandProperties()
var props = new SlashCommandProperties
{ {
Name = Name, Name = Name,
Description = Description, Description = Description,
@@ -160,12 +150,14 @@ namespace Discord
/// <param name="description">The description of this option.</param> /// <param name="description">The description of this option.</param>
/// <param name="isRequired">If this option is required for this command.</param> /// <param name="isRequired">If this option is required for this command.</param>
/// <param name="isDefault">If this option is the default option.</param> /// <param name="isDefault">If this option is the default option.</param>
/// <param name="isAutocomplete">If this option is set to autocompleate.</param>
/// <param name="isAutocomplete">If this option is set to autocomplete.</param>
/// <param name="options">The options of the option to add.</param> /// <param name="options">The options of the option to add.</param>
/// <param name="channelTypes">The allowed channel types for this option.</param>
/// <param name="choices">The choices of this option.</param> /// <param name="choices">The choices of this option.</param>
/// <returns>The current builder.</returns> /// <returns>The current builder.</returns>
public SlashCommandBuilder AddOption(string name, ApplicationCommandOptionType type, public SlashCommandBuilder AddOption(string name, ApplicationCommandOptionType type,
string description, bool? isRequired = null, bool? isDefault = null, bool isAutocomplete = false, List<SlashCommandOptionBuilder> options = null, params ApplicationCommandOptionChoiceProperties[] choices)
string description, bool? isRequired = null, bool? isDefault = null, bool isAutocomplete = false, List<SlashCommandOptionBuilder> options = null,
List<ChannelType> channelTypes = null, params ApplicationCommandOptionChoiceProperties[] choices)
{ {
// Make sure the name matches the requirements from discord // Make sure the name matches the requirements from discord
Preconditions.NotNullOrEmpty(name, nameof(name)); Preconditions.NotNullOrEmpty(name, nameof(name));
@@ -175,7 +167,7 @@ namespace Discord
// Discord updated the docs, this regex prevents special characters like @!$%( and s p a c e s.. etc, // Discord updated the docs, this regex prevents special characters like @!$%( and s p a c e s.. etc,
// https://discord.com/developers/docs/interactions/slash-commands#applicationcommand // https://discord.com/developers/docs/interactions/slash-commands#applicationcommand
if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) if (!Regex.IsMatch(name, @"^[\w-]{1,32}$"))
throw new ArgumentException("Command name cannot contian any special characters or whitespaces!", nameof(name));
throw new ArgumentException("Command name cannot contain any special characters or whitespaces!", nameof(name));


// same with description // same with description
Preconditions.NotNullOrEmpty(description, nameof(description)); Preconditions.NotNullOrEmpty(description, nameof(description));
@@ -183,14 +175,10 @@ namespace Discord
Preconditions.AtMost(description.Length, MaxDescriptionLength, nameof(description)); Preconditions.AtMost(description.Length, MaxDescriptionLength, nameof(description));


// make sure theres only one option with default set to true // make sure theres only one option with default set to true
if (isDefault.HasValue && isDefault.Value)
{
if (Options != null)
if (Options.Any(x => x.IsDefault.HasValue && x.IsDefault.Value))
throw new ArgumentException("There can only be one command option with default set to true!", nameof(isDefault));
}
if (isDefault == true && Options?.Any(x => x.IsDefault == true) == true)
throw new ArgumentException("There can only be one command option with default set to true!", nameof(isDefault));


SlashCommandOptionBuilder option = new SlashCommandOptionBuilder
var option = new SlashCommandOptionBuilder
{ {
Name = name, Name = name,
Description = description, Description = description,
@@ -199,7 +187,8 @@ namespace Discord
Options = options, Options = options,
Type = type, Type = type,
IsAutocomplete = isAutocomplete, IsAutocomplete = isAutocomplete,
Choices = choices != null ? new List<ApplicationCommandOptionChoiceProperties>(choices) : null
Choices = (choices ?? Array.Empty<ApplicationCommandOptionChoiceProperties>()).ToList(),
ChannelTypes = channelTypes
}; };


return AddOption(option); return AddOption(option);
@@ -212,14 +201,12 @@ namespace Discord
/// <returns>The current builder.</returns> /// <returns>The current builder.</returns>
public SlashCommandBuilder AddOption(SlashCommandOptionBuilder option) public SlashCommandBuilder AddOption(SlashCommandOptionBuilder option)
{ {
if (Options == null)
Options = new List<SlashCommandOptionBuilder>();
Options ??= new List<SlashCommandOptionBuilder>();


if (Options.Count >= MaxOptionsCount) if (Options.Count >= MaxOptionsCount)
throw new ArgumentOutOfRangeException(nameof(Options), $"Cannot have more than {MaxOptionsCount} options!");
throw new InvalidOperationException($"Cannot have more than {MaxOptionsCount} options!");


if (option == null)
throw new ArgumentNullException(nameof(option), "Option cannot be null");
Preconditions.NotNull(option, nameof(option));


Options.Add(option); Options.Add(option);
return this; return this;
@@ -235,10 +222,9 @@ namespace Discord
throw new ArgumentNullException(nameof(options), "Options cannot be null!"); throw new ArgumentNullException(nameof(options), "Options cannot be null!");


if (options.Length == 0) if (options.Length == 0)
throw new ArgumentException(nameof(options), "Options cannot be empty!");
throw new ArgumentException("Options cannot be empty!", nameof(options));


if (Options == null)
Options = new List<SlashCommandOptionBuilder>();
Options ??= new List<SlashCommandOptionBuilder>();


if (Options.Count + options.Length > MaxOptionsCount) if (Options.Count + options.Length > MaxOptionsCount)
throw new ArgumentOutOfRangeException(nameof(options), $"Cannot have more than {MaxOptionsCount} options!"); throw new ArgumentOutOfRangeException(nameof(options), $"Cannot have more than {MaxOptionsCount} options!");
@@ -274,14 +260,13 @@ namespace Discord
get => _name; get => _name;
set set
{ {
if (value?.Length > SlashCommandBuilder.MaxNameLength)
throw new ArgumentException($"Name length must be less than or equal to {SlashCommandBuilder.MaxNameLength}");
if (value?.Length < 1)
throw new ArgumentException("Name length must at least 1 characters in length");

if (value != null) if (value != null)
{
Preconditions.AtLeast(value.Length, 1, nameof(value));
Preconditions.AtMost(value.Length, SlashCommandBuilder.MaxNameLength, nameof(value));
if (!Regex.IsMatch(value, @"^[\w-]{1,32}$")) if (!Regex.IsMatch(value, @"^[\w-]{1,32}$"))
throw new ArgumentException("Option name cannot contian any special characters or whitespaces!");
throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(value));
}


_name = value; _name = value;
} }
@@ -295,10 +280,11 @@ namespace Discord
get => _description; get => _description;
set set
{ {
if (value?.Length > SlashCommandBuilder.MaxDescriptionLength)
throw new ArgumentException($"Description length must be less than or equal to {SlashCommandBuilder.MaxDescriptionLength}");
if (value?.Length < 1)
throw new ArgumentException("Description length must at least 1 character in length");
if (value != null)
{
Preconditions.AtLeast(value.Length, 1, nameof(value));
Preconditions.AtMost(value.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(value));
}


_description = value; _description = value;
} }
@@ -334,6 +320,11 @@ namespace Discord
/// </summary> /// </summary>
public List<SlashCommandOptionBuilder> Options { get; set; } public List<SlashCommandOptionBuilder> Options { get; set; }


/// <summary>
/// Gets or sets the allowed channel types for this option.
/// </summary>
public List<ChannelType> ChannelTypes { get; set; }

/// <summary> /// <summary>
/// Builds the current option. /// Builds the current option.
/// </summary> /// </summary>
@@ -343,21 +334,22 @@ namespace Discord
bool isSubType = Type == ApplicationCommandOptionType.SubCommandGroup; bool isSubType = Type == ApplicationCommandOptionType.SubCommandGroup;


if (isSubType && (Options == null || !Options.Any())) if (isSubType && (Options == null || !Options.Any()))
throw new ArgumentException(nameof(Options), "SubCommands/SubCommandGroups must have at least one option");
throw new InvalidOperationException("SubCommands/SubCommandGroups must have at least one option");


if (!isSubType && (Options != null && Options.Any()) && Type != ApplicationCommandOptionType.SubCommand)
throw new ArgumentException(nameof(Options), $"Cannot have options on {Type} type");
if (!isSubType && Options != null && Options.Any() && Type != ApplicationCommandOptionType.SubCommand)
throw new InvalidOperationException($"Cannot have options on {Type} type");


return new ApplicationCommandOptionProperties()
return new ApplicationCommandOptionProperties
{ {
Name = Name, Name = Name,
Description = Description, Description = Description,
IsDefault = IsDefault, IsDefault = IsDefault,
IsRequired = IsRequired, IsRequired = IsRequired,
Type = Type, Type = Type,
Options = Options?.Count > 0 ? new List<ApplicationCommandOptionProperties>(Options.Select(x => x.Build())) : null,
Options = Options?.Count > 0 ? Options.Select(x => x.Build()).ToList() : new List<ApplicationCommandOptionProperties>(),
Choices = Choices, Choices = Choices,
IsAutocomplete = IsAutocomplete
IsAutocomplete = IsAutocomplete,
ChannelTypes = ChannelTypes
}; };
} }


@@ -369,11 +361,14 @@ namespace Discord
/// <param name="description">The description of this option.</param> /// <param name="description">The description of this option.</param>
/// <param name="isRequired">If this option is required for this command.</param> /// <param name="isRequired">If this option is required for this command.</param>
/// <param name="isDefault">If this option is the default option.</param> /// <param name="isDefault">If this option is the default option.</param>
/// <param name="isAutocomplete">If this option supports autocomplete.</param>
/// <param name="options">The options of the option to add.</param> /// <param name="options">The options of the option to add.</param>
/// <param name="channelTypes">The allowed channel types for this option.</param>
/// <param name="choices">The choices of this option.</param> /// <param name="choices">The choices of this option.</param>
/// <returns>The current builder.</returns> /// <returns>The current builder.</returns>
public SlashCommandOptionBuilder AddOption(string name, ApplicationCommandOptionType type, public SlashCommandOptionBuilder AddOption(string name, ApplicationCommandOptionType type,
string description, bool? isRequired = null, bool isDefault = false, bool isAutocomplete = false, List<SlashCommandOptionBuilder> options = null, params ApplicationCommandOptionChoiceProperties[] choices)
string description, bool? isRequired = null, bool isDefault = false, bool isAutocomplete = false, List<SlashCommandOptionBuilder> options = null,
List<ChannelType> channelTypes = null, params ApplicationCommandOptionChoiceProperties[] choices)
{ {
// Make sure the name matches the requirements from discord // Make sure the name matches the requirements from discord
Preconditions.NotNullOrEmpty(name, nameof(name)); Preconditions.NotNullOrEmpty(name, nameof(name));
@@ -383,7 +378,7 @@ namespace Discord
// Discord updated the docs, this regex prevents special characters like @!$%( and s p a c e s.. etc, // Discord updated the docs, this regex prevents special characters like @!$%( and s p a c e s.. etc,
// https://discord.com/developers/docs/interactions/slash-commands#applicationcommand // https://discord.com/developers/docs/interactions/slash-commands#applicationcommand
if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) if (!Regex.IsMatch(name, @"^[\w-]{1,32}$"))
throw new ArgumentException("Command name cannot contian any special characters or whitespaces!", nameof(name));
throw new ArgumentException("Command name cannot contain any special characters or whitespaces!", nameof(name));


// same with description // same with description
Preconditions.NotNullOrEmpty(description, nameof(description)); Preconditions.NotNullOrEmpty(description, nameof(description));
@@ -391,14 +386,10 @@ namespace Discord
Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description)); Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description));


// make sure theres only one option with default set to true // make sure theres only one option with default set to true
if (isDefault)
{
if (Options != null)
if (Options.Any(x => x.IsDefault.HasValue && x.IsDefault.Value))
throw new ArgumentException("There can only be one command option with default set to true!", nameof(isDefault));
}
if (isDefault && Options?.Any(x => x.IsDefault == true) == true)
throw new ArgumentException("There can only be one command option with default set to true!", nameof(isDefault));


SlashCommandOptionBuilder option = new SlashCommandOptionBuilder
var option = new SlashCommandOptionBuilder
{ {
Name = name, Name = name,
Description = description, Description = description,
@@ -407,7 +398,8 @@ namespace Discord
IsDefault = isDefault, IsDefault = isDefault,
Options = options, Options = options,
Type = type, Type = type,
Choices = choices != null ? new List<ApplicationCommandOptionChoiceProperties>(choices) : null
Choices = (choices ?? Array.Empty<ApplicationCommandOptionChoiceProperties>()).ToList(),
ChannelTypes = channelTypes
}; };


return AddOption(option); return AddOption(option);
@@ -419,14 +411,12 @@ namespace Discord
/// <returns>The current builder.</returns> /// <returns>The current builder.</returns>
public SlashCommandOptionBuilder AddOption(SlashCommandOptionBuilder option) public SlashCommandOptionBuilder AddOption(SlashCommandOptionBuilder option)
{ {
if (Options == null)
Options = new List<SlashCommandOptionBuilder>();
Options ??= new List<SlashCommandOptionBuilder>();


if (Options.Count >= SlashCommandBuilder.MaxOptionsCount) if (Options.Count >= SlashCommandBuilder.MaxOptionsCount)
throw new ArgumentOutOfRangeException(nameof(Choices), $"There can only be {SlashCommandBuilder.MaxOptionsCount} options per sub command group!");
throw new InvalidOperationException($"There can only be {SlashCommandBuilder.MaxOptionsCount} options per sub command group!");


if (option == null)
throw new ArgumentNullException(nameof(option), "Option cannot be null");
Preconditions.NotNull(option, nameof(option));


Options.Add(option); Options.Add(option);
return this; return this;
@@ -489,17 +479,13 @@ namespace Discord


private SlashCommandOptionBuilder AddChoiceInternal(string name, object value) private SlashCommandOptionBuilder AddChoiceInternal(string name, object value)
{ {
if (Choices == null)
Choices = new List<ApplicationCommandOptionChoiceProperties>();
Choices ??= new List<ApplicationCommandOptionChoiceProperties>();


if (Choices.Count >= MaxChoiceCount) if (Choices.Count >= MaxChoiceCount)
throw new ArgumentOutOfRangeException(nameof(Choices), $"Cannot add more than {MaxChoiceCount} choices!");

if (name == null)
throw new ArgumentNullException($"{nameof(name)} cannot be null!");
throw new InvalidOperationException($"Cannot add more than {MaxChoiceCount} choices!");


if (value == null)
throw new ArgumentNullException($"{nameof(value)} cannot be null!");
Preconditions.NotNull(name, nameof(name));
Preconditions.NotNull(value, nameof(value));


Preconditions.AtLeast(name.Length, 1, nameof(name)); Preconditions.AtLeast(name.Length, 1, nameof(name));
Preconditions.AtMost(name.Length, 100, nameof(name)); Preconditions.AtMost(name.Length, 100, nameof(name));
@@ -510,7 +496,7 @@ namespace Discord
Preconditions.AtMost(str.Length, 100, nameof(value)); Preconditions.AtMost(str.Length, 100, nameof(value));
} }


Choices.Add(new ApplicationCommandOptionChoiceProperties()
Choices.Add(new ApplicationCommandOptionChoiceProperties
{ {
Name = name, Name = name,
Value = value Value = value
@@ -519,6 +505,20 @@ namespace Discord
return this; return this;
} }


/// <summary>
/// Adds a channel type to the current option.
/// </summary>
/// <param name="channelType">The <see cref="ChannelType"/> to add.</param>
/// <returns>The current builder.</returns>
public SlashCommandOptionBuilder AddChannelType(ChannelType channelType)
{
ChannelTypes ??= new List<ChannelType>();

ChannelTypes.Add(channelType);

return this;
}

/// <summary> /// <summary>
/// Sets the current builders name. /// Sets the current builders name.
/// </summary> /// </summary>
@@ -564,6 +564,17 @@ namespace Discord
return this; return this;
} }


/// <summary>
/// Sets the current builders autocomplete field.
/// </summary>
/// <param name="value">The value to set.</param>
/// <returns>The current builder.</returns>
public SlashCommandOptionBuilder WithAutocomplete(bool value)
{
IsAutocomplete = value;
return this;
}

/// <summary> /// <summary>
/// Sets the current type of this builder. /// Sets the current type of this builder.
/// </summary> /// </summary>


+ 0
- 4
src/Discord.Net.Core/Entities/Interactions/Slash Commands/SlashCommandProperties.cs View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {


+ 7
- 7
src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs View File

@@ -408,22 +408,22 @@ namespace Discord
if (Length > MaxEmbedLength) if (Length > MaxEmbedLength)
throw new InvalidOperationException($"Total embed length must be less than or equal to {MaxEmbedLength}."); throw new InvalidOperationException($"Total embed length must be less than or equal to {MaxEmbedLength}.");
if (!string.IsNullOrEmpty(Url)) if (!string.IsNullOrEmpty(Url))
UrlValidation.Validate(Url);
UrlValidation.Validate(Url, true);
if (!string.IsNullOrEmpty(ThumbnailUrl)) if (!string.IsNullOrEmpty(ThumbnailUrl))
UrlValidation.Validate(ThumbnailUrl);
if (!string.IsNullOrEmpty(ImageUrl) && !ImageUrl.StartsWith("attachment://", StringComparison.Ordinal))
UrlValidation.Validate(ImageUrl);
UrlValidation.Validate(ThumbnailUrl, true);
if (!string.IsNullOrEmpty(ImageUrl))
UrlValidation.Validate(ImageUrl, true);
if (Author != null) if (Author != null)
{ {
if (!string.IsNullOrEmpty(Author.Url)) if (!string.IsNullOrEmpty(Author.Url))
UrlValidation.Validate(Author.Url);
UrlValidation.Validate(Author.Url, true);
if (!string.IsNullOrEmpty(Author.IconUrl)) if (!string.IsNullOrEmpty(Author.IconUrl))
UrlValidation.Validate(Author.IconUrl);
UrlValidation.Validate(Author.IconUrl, true);
} }
if(Footer != null) if(Footer != null)
{ {
if (!string.IsNullOrEmpty(Footer.IconUrl)) if (!string.IsNullOrEmpty(Footer.IconUrl))
UrlValidation.Validate(Footer.IconUrl);
UrlValidation.Validate(Footer.IconUrl, true);
} }
var fields = ImmutableArray.CreateBuilder<EmbedField>(Fields.Count); var fields = ImmutableArray.CreateBuilder<EmbedField>(Fields.Count);
for (int i = 0; i < Fields.Count; i++) for (int i = 0; i < Fields.Count; i++)


+ 7
- 0
src/Discord.Net.Core/Entities/Messages/IAttachment.cs View File

@@ -55,5 +55,12 @@ namespace Discord
/// The width of this attachment if it is a picture; otherwise <c>null</c>. /// The width of this attachment if it is a picture; otherwise <c>null</c>.
/// </returns> /// </returns>
int? Width { get; } int? Width { get; }
/// <summary>
/// Gets whether or not this attachment is ephemeral.
/// </summary>
/// <returns>
/// <see langword="true"/> if the attachment is ephemeral; otherwise <see langword="false"/>.
/// </returns>
bool Ephemeral { get; }
} }
} }

+ 16
- 1
src/Discord.Net.Core/Entities/Messages/IMessage.cs View File

@@ -53,6 +53,13 @@ namespace Discord
/// </returns> /// </returns>
string Content { get; } string Content { get; }
/// <summary> /// <summary>
/// Gets the clean content for this message.
/// </summary>
/// <returns>
/// A string that contains the body of the message stripped of mentions, markdown, emojis and pings; note that this field may be empty if there is an embed.
/// </returns>
string CleanContent { get; }
/// <summary>
/// Gets the time this message was sent. /// Gets the time this message was sent.
/// </summary> /// </summary>
/// <returns> /// <returns>
@@ -187,7 +194,15 @@ namespace Discord
/// A message's flags, if any is associated. /// A message's flags, if any is associated.
/// </returns> /// </returns>
MessageFlags? Flags { get; } MessageFlags? Flags { get; }

/// <summary>
/// Gets the interaction this message is a response to.
/// </summary>
/// <returns>
/// A <see cref="IMessageInteraction"/> if the message is a response to an interaction; otherwise <see langword="null"/>.
/// </returns>
IMessageInteraction Interaction { get; }

/// <summary> /// <summary>
/// Adds a reaction to this message. /// Adds a reaction to this message.
/// </summary> /// </summary>


+ 34
- 0
src/Discord.Net.Core/Entities/Messages/IMessageInteraction.cs View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents a partial <see cref="IDiscordInteraction"/> within a message.
/// </summary>
public interface IMessageInteraction
{
/// <summary>
/// Gets the snowflake id of the interaction.
/// </summary>
ulong Id { get; }

/// <summary>
/// Gets the type of the interaction.
/// </summary>
InteractionType Type { get; }

/// <summary>
/// Gets the name of the application command used.
/// </summary>
string Name { get; }

/// <summary>
/// Gets the <seealso cref="IUser"/> who invoked the interaction.
/// </summary>
IUser User { get; }
}
}

+ 45
- 0
src/Discord.Net.Core/Entities/Messages/MessageInteraction.cs View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents a partial <see cref="IDiscordInteraction"/> within a message.
/// </summary>
/// <typeparam name="TUser">The type of the user.</typeparam>
public class MessageInteraction<TUser> : IMessageInteraction where TUser : IUser
{
/// <summary>
/// Gets the snowflake id of the interaction.
/// </summary>
public ulong Id { get; }

/// <summary>
/// Gets the type of the interaction.
/// </summary>
public InteractionType Type { get; }

/// <summary>
/// Gets the name of the application command used.
/// </summary>
public string Name { get; }

/// <summary>
/// Gets the <typeparamref name="TUser"/> who invoked the interaction.
/// </summary>
public TUser User { get; }

internal MessageInteraction(ulong id, InteractionType type, string name, TUser user)
{
Id = id;
Type = type;
Name = name;
User = user;
}

IUser IMessageInteraction.User => User;
}
}

+ 10
- 6
src/Discord.Net.Core/Entities/Messages/MessageType.cs View File

@@ -81,26 +81,30 @@ namespace Discord
/// The message is an inline reply. /// The message is an inline reply.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Only available in API v8
/// Only available in API v8.
/// </remarks> /// </remarks>
Reply = 19, Reply = 19,
/// <summary> /// <summary>
/// The message is an Application Command
/// The message is an Application Command.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Only available in API v8
/// Only available in API v8.
/// </remarks> /// </remarks>
ApplicationCommand = 20, ApplicationCommand = 20,
/// <summary> /// <summary>
/// The message that starts a thread. /// The message that starts a thread.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Only available in API v9
/// Only available in API v9.
/// </remarks> /// </remarks>
ThreadStarterMessage = 21, ThreadStarterMessage = 21,
/// <summary> /// <summary>
/// The message for a invite reminder
/// The message for a invite reminder.
/// </summary> /// </summary>
GuildInviteReminder = 22
GuildInviteReminder = 22,
/// <summary>
/// The message for a context menu command.
/// </summary>
ContextMenuCommand = 23,
} }
} }

+ 16
- 6
src/Discord.Net.Core/Entities/Messages/StickerFormatType.cs View File

@@ -1,15 +1,25 @@
namespace Discord namespace Discord
{ {
/// <summary> Defines the types of formats for stickers. </summary>
/// <summary>
/// Defines the types of formats for stickers.
/// </summary>
public enum StickerFormatType public enum StickerFormatType
{ {
/// <summary> Default value for a sticker format type. </summary>
/// <summary>
/// Default value for a sticker format type.
/// </summary>
None = 0, None = 0,
/// <summary> The sticker format type is png. </summary>
/// <summary>
/// The sticker format type is png.
/// </summary>
Png = 1, Png = 1,
/// <summary> The sticker format type is apng. </summary>
/// <summary>
/// The sticker format type is apng.
/// </summary>
Apng = 2, Apng = 2,
/// <summary> The sticker format type is lottie. </summary>
Lottie = 3,
/// <summary>
/// The sticker format type is lottie.
/// </summary>
Lottie = 3
} }
} }

+ 4
- 13
src/Discord.Net.Core/Entities/Messages/TimestampTag.cs View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {
@@ -24,18 +20,13 @@ namespace Discord
/// <summary> /// <summary>
/// Converts the current timestamp tag to the string representation supported by discord. /// Converts the current timestamp tag to the string representation supported by discord.
/// <para> /// <para>
/// If the <see cref="TimestampTag.Time"/> is null then the default 0 will be used.
/// If the <see cref="Time"/> is null then the default 0 will be used.
/// </para> /// </para>
/// </summary> /// </summary>
/// <returns>A string thats compatable in a discord message, ex: <code>&lt;t:1625944201:f&gt;</code></returns>
/// <returns>A string that is compatible in a discord message, ex: <code>&lt;t:1625944201:f&gt;</code></returns>
public override string ToString() public override string ToString()
{ {
if (Time == null)
return $"<t:0:{(char)Style}>";

var offset = (DateTimeOffset)this.Time;

return $"<t:{offset.ToUnixTimeSeconds()}:{(char)Style}>";
return $"<t:{((DateTimeOffset)Time).ToUnixTimeSeconds()}:{(char)Style}>";
} }


/// <summary> /// <summary>
@@ -46,7 +37,7 @@ namespace Discord
/// <returns>The newly create timestamp tag.</returns> /// <returns>The newly create timestamp tag.</returns>
public static TimestampTag FromDateTime(DateTime time, TimestampTagStyles style = TimestampTagStyles.ShortDateTime) public static TimestampTag FromDateTime(DateTime time, TimestampTagStyles style = TimestampTagStyles.ShortDateTime)
{ {
return new TimestampTag()
return new TimestampTag
{ {
Style = style, Style = style,
Time = time Time = time


+ 0
- 6
src/Discord.Net.Core/Entities/Messages/TimestampTagStyle.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>


+ 1
- 7
src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissionTarget.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
@@ -18,6 +12,6 @@ namespace Discord
/// <summary> /// <summary>
/// The target of the permission is a user. /// The target of the permission is a user.
/// </summary> /// </summary>
User = 2,
User = 2
} }
} }

+ 0
- 17
src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs View File

@@ -110,12 +110,6 @@ namespace Discord
/// </summary> /// </summary>
ManageEmojis = 0x00_40_00_00_00, ManageEmojis = 0x00_40_00_00_00,


/// <summary>
/// Allows members to use slash commands in text channels.
/// </summary>
[Obsolete("UseSlashCommands has been replaced by UseApplicationCommands", true)]
UseSlashCommands = 0x00_80_00_00_00,

/// <summary> /// <summary>
/// Allows members to use slash commands in text channels. /// Allows members to use slash commands in text channels.
/// </summary> /// </summary>
@@ -131,17 +125,6 @@ namespace Discord
/// </summary> /// </summary>
ManageThreads = 0x04_00_00_00_00, ManageThreads = 0x04_00_00_00_00,


/// <summary>
/// Allows for creating and participating in threads
/// </summary>
[Obsolete("UsePublicThreads has been replaced by CreatePublicThreads and SendMessagesInThreads", true)]
UsePublicThreads = 0x08_00_00_00_00,

/// <summary>
/// Allows for creating and participating in private threads
/// </summary>
[Obsolete("UsePrivateThreads has been replaced by CreatePrivateThreads and SendMessagesInThreads", true)]
UsePrivateThreads = 0x10_00_00_00_00,
/// <summary> /// <summary>
/// Allows for creating public threads. /// Allows for creating public threads.
/// </summary> /// </summary>


+ 2
- 2
src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs View File

@@ -85,7 +85,7 @@ namespace Discord
/// <summary> If <c>true</c>, a user may stream video in a voice channel.</summary> /// <summary> If <c>true</c>, a user may stream video in a voice channel.</summary>
public bool Stream => Permissions.GetValue(RawValue, ChannelPermission.Stream); public bool Stream => Permissions.GetValue(RawValue, ChannelPermission.Stream);


/// <summary> If <c>true</c>, a user may adjust role permissions. This also implictly grants all other permissions.</summary>
/// <summary> If <c>true</c>, a user may adjust role permissions. This also implicitly grants all other permissions.</summary>
public bool ManageRoles => Permissions.GetValue(RawValue, ChannelPermission.ManageRoles); public bool ManageRoles => Permissions.GetValue(RawValue, ChannelPermission.ManageRoles);
/// <summary> If <c>true</c>, a user may edit the webhooks for this channel.</summary> /// <summary> If <c>true</c>, a user may edit the webhooks for this channel.</summary>
public bool ManageWebhooks => Permissions.GetValue(RawValue, ChannelPermission.ManageWebhooks); public bool ManageWebhooks => Permissions.GetValue(RawValue, ChannelPermission.ManageWebhooks);
@@ -103,7 +103,7 @@ namespace Discord
public bool UseExternalStickers => Permissions.GetValue(RawValue, ChannelPermission.UseExternalStickers); public bool UseExternalStickers => Permissions.GetValue(RawValue, ChannelPermission.UseExternalStickers);
/// <summary> If <c>true</c>, a user may send messages in threads in this guild.</summary> /// <summary> If <c>true</c>, a user may send messages in threads in this guild.</summary>
public bool SendMessagesInThreads => Permissions.GetValue(RawValue, ChannelPermission.SendMessagesInThreads); public bool SendMessagesInThreads => Permissions.GetValue(RawValue, ChannelPermission.SendMessagesInThreads);
/// <summary> If <c>true</c>, a user launch application activites in voice channels in this guild.</summary>
/// <summary> If <c>true</c>, a user launch application activities in voice channels in this guild.</summary>
public bool StartEmbeddedActivities => Permissions.GetValue(RawValue, ChannelPermission.StartEmbeddedActivities); public bool StartEmbeddedActivities => Permissions.GetValue(RawValue, ChannelPermission.StartEmbeddedActivities);


/// <summary> Creates a new <see cref="ChannelPermissions"/> with the provided packed value.</summary> /// <summary> Creates a new <see cref="ChannelPermissions"/> with the provided packed value.</summary>


+ 0
- 4
src/Discord.Net.Core/Entities/Permissions/GuildApplicationCommandPermissions.cs View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {


+ 0
- 15
src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs View File

@@ -176,11 +176,6 @@ namespace Discord
/// </remarks> /// </remarks>
ManageEmojisAndStickers = 0x40_00_00_00, ManageEmojisAndStickers = 0x40_00_00_00,
/// <summary> /// <summary>
/// Allows members to use slash commands in text channels.
/// </summary>
[Obsolete("UseSlashCommands has been replaced by UseApplicationCommands", true)]
UseSlashCommands = 0x80_00_00_00,
/// <summary>
/// Allows members to use application commands like slash commands and context menus in text channels. /// Allows members to use application commands like slash commands and context menus in text channels.
/// </summary> /// </summary>
UseApplicationCommands = 0x80_00_00_00, UseApplicationCommands = 0x80_00_00_00,
@@ -205,16 +200,6 @@ namespace Discord
/// </summary> /// </summary>
CreatePrivateThreads = 0x10_00_00_00_00, CreatePrivateThreads = 0x10_00_00_00_00,
/// <summary> /// <summary>
/// Allows for creating public threads.
/// </summary>
[Obsolete("UsePublicThreads has been replaced by CreatePublicThreads and SendMessagesInThreads", true)]
UsePublicThreads = 0x08_00_00_00_00,
/// <summary>
/// Allows for creating private threads.
/// </summary>
[Obsolete("UsePrivateThreads has been replaced by CreatePrivateThreads and SendMessagesInThreads", true)]
UsePrivateThreads = 0x10_00_00_00_00,
/// <summary>
/// Allows the usage of custom stickers from other servers. /// Allows the usage of custom stickers from other servers.
/// </summary> /// </summary>
UseExternalStickers = 0x20_00_00_00_00, UseExternalStickers = 0x20_00_00_00_00,


+ 1
- 1
src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs View File

@@ -97,7 +97,7 @@ namespace Discord
public bool UseExternalStickers => Permissions.GetValue(RawValue, GuildPermission.UseExternalStickers); public bool UseExternalStickers => Permissions.GetValue(RawValue, GuildPermission.UseExternalStickers);
/// <summary> If <c>true</c>, a user may send messages in threads in this guild. </summary> /// <summary> If <c>true</c>, a user may send messages in threads in this guild. </summary>
public bool SendMessagesInThreads => Permissions.GetValue(RawValue, GuildPermission.SendMessagesInThreads); public bool SendMessagesInThreads => Permissions.GetValue(RawValue, GuildPermission.SendMessagesInThreads);
/// <summary> If <c>true</c>, a user launch application activites in voice channels in this guild. </summary>
/// <summary> If <c>true</c>, a user launch application activities in voice channels in this guild. </summary>
public bool StartEmbeddedActivities => Permissions.GetValue(RawValue, GuildPermission.StartEmbeddedActivities); public bool StartEmbeddedActivities => Permissions.GetValue(RawValue, GuildPermission.StartEmbeddedActivities);


/// <summary> Creates a new <see cref="GuildPermissions"/> with the provided packed value. </summary> /// <summary> Creates a new <see cref="GuildPermissions"/> with the provided packed value. </summary>


+ 1
- 1
src/Discord.Net.Core/Entities/Permissions/OverwritePermissions.cs View File

@@ -97,7 +97,7 @@ namespace Discord
public PermValue UseExternalStickers => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.UseExternalStickers); public PermValue UseExternalStickers => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.UseExternalStickers);
/// <summary> If <c>true</c>, a user may send messages in threads in this guild. </summary> /// <summary> If <c>true</c>, a user may send messages in threads in this guild. </summary>
public PermValue SendMessagesInThreads => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.SendMessagesInThreads); public PermValue SendMessagesInThreads => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.SendMessagesInThreads);
/// <summary> If <c>true</c>, a user launch application activites in voice channels in this guild. </summary>
/// <summary> If <c>true</c>, a user launch application activities in voice channels in this guild. </summary>
public PermValue StartEmbeddedActivities => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.StartEmbeddedActivities); public PermValue StartEmbeddedActivities => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.StartEmbeddedActivities);


/// <summary> Creates a new OverwritePermissions with the provided allow and deny packed values. </summary> /// <summary> Creates a new OverwritePermissions with the provided allow and deny packed values. </summary>


+ 15
- 0
src/Discord.Net.Core/Entities/Roles/IRole.cs View File

@@ -52,6 +52,13 @@ namespace Discord
/// </returns> /// </returns>
string Name { get; } string Name { get; }
/// <summary> /// <summary>
/// Gets the icon of this role.
/// </summary>
/// <returns>
/// A string containing the hash of this role's icon.
/// </returns>
string Icon { get; }
/// <summary>
/// Gets the permissions granted to members of this role. /// Gets the permissions granted to members of this role.
/// </summary> /// </summary>
/// <returns> /// <returns>
@@ -86,5 +93,13 @@ namespace Discord
/// A task that represents the asynchronous modification operation. /// A task that represents the asynchronous modification operation.
/// </returns> /// </returns>
Task ModifyAsync(Action<RoleProperties> func, RequestOptions options = null); Task ModifyAsync(Action<RoleProperties> func, RequestOptions options = null);

/// <summary>
/// Gets the image url of the icon role.
/// </summary>
/// <returns>
/// An image url of the icon role.
/// </returns>
string GetIconUrl();
} }
} }

+ 1
- 4
src/Discord.Net.Core/Entities/Stickers/ICustomSticker.cs View File

@@ -1,7 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;


namespace Discord namespace Discord
@@ -51,7 +48,7 @@ namespace Discord
/// Deletes the current sticker. /// Deletes the current sticker.
/// </summary> /// </summary>
/// <remakrs> /// <remakrs>
/// The bot neeeds the MANAGE_EMOJIS_AND_STICKERS permission inside the guild in order to delete stickers.
/// The bot needs the MANAGE_EMOJIS_AND_STICKERS permission inside the guild in order to delete stickers.
/// </remakrs> /// </remakrs>
/// <param name="options">The options to be used when sending the request.</param> /// <param name="options">The options to be used when sending the request.</param>
/// <returns> /// <returns>


+ 2
- 4
src/Discord.Net.Core/Entities/Stickers/ISticker.cs View File

@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {
@@ -57,12 +55,12 @@ namespace Discord
new StickerFormatType Format { get; } new StickerFormatType Format { get; }


/// <summary> /// <summary>
/// Gets whether this guild sticker can be used, may be false due to loss of Server Boosts
/// Gets whether this guild sticker can be used, may be false due to loss of Server Boosts.
/// </summary> /// </summary>
bool? IsAvailable { get; } bool? IsAvailable { get; }


/// <summary> /// <summary>
/// Gets the standard sticker's sort order within its pack
/// Gets the standard sticker's sort order within its pack.
/// </summary> /// </summary>
int? SortOrder { get; } int? SortOrder { get; }
/// <summary> /// <summary>


+ 0
- 6
src/Discord.Net.Core/Entities/Stickers/IStickerItem.cs View File

@@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>


+ 1
- 5
src/Discord.Net.Core/Entities/Stickers/StickerPack.cs View File

@@ -1,16 +1,12 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
/// Represents a discord sticker pack. /// Represents a discord sticker pack.
/// </summary> /// </summary>
/// <typeparam name="TSticker">The type of the stickers within the collection</typeparam>
/// <typeparam name="TSticker">The type of the stickers within the collection.</typeparam>
public class StickerPack<TSticker> where TSticker : ISticker public class StickerPack<TSticker> where TSticker : ISticker
{ {
/// <summary> /// <summary>


+ 0
- 4
src/Discord.Net.Core/Entities/Stickers/StickerProperties.cs View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord namespace Discord
{ {


+ 2
- 8
src/Discord.Net.Core/Entities/Stickers/StickerType.cs View File

@@ -1,13 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord namespace Discord
{ {
/// <summary> /// <summary>
/// Represents a type of sticker
/// Represents a type of sticker..
/// </summary> /// </summary>
public enum StickerType public enum StickerType
{ {
@@ -19,6 +13,6 @@ namespace Discord
/// <summary> /// <summary>
/// Represents a sticker that was created within a guild. /// Represents a sticker that was created within a guild.
/// </summary> /// </summary>
Guild = 2,
Guild = 2
} }
} }

+ 2
- 2
src/Discord.Net.Core/Extensions/MessageExtensions.cs View File

@@ -24,7 +24,7 @@ namespace Discord
/// Add multiple reactions to a message. /// Add multiple reactions to a message.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This method does not bulk add reactions! It will send a request for each reaction inculded.
/// This method does not bulk add reactions! It will send a request for each reaction included.
/// </remarks> /// </remarks>
/// <example> /// <example>
/// <code language="cs"> /// <code language="cs">
@@ -76,7 +76,7 @@ namespace Discord
/// <summary> /// <summary>
/// Sends an inline reply that references a message. /// Sends an inline reply that references a message.
/// </summary> /// </summary>
/// <param name="msg">The message that is being replyed on.</param>
/// <param name="msg">The message that is being replied on.</param>
/// <param name="text">The message to be sent.</param> /// <param name="text">The message to be sent.</param>
/// <param name="isTTS">Determines whether the message should be read aloud by Discord or not.</param> /// <param name="isTTS">Determines whether the message should be read aloud by Discord or not.</param>
/// <param name="embed">The <see cref="Discord.EmbedType.Rich"/> <see cref="Embed"/> to be sent.</param> /// <param name="embed">The <see cref="Discord.EmbedType.Rich"/> <see cref="Embed"/> to be sent.</param>


+ 14
- 1
src/Discord.Net.Core/Format.cs View File

@@ -1,4 +1,5 @@
using System.Text; using System.Text;
using System.Text.RegularExpressions;


namespace Discord namespace Discord
{ {
@@ -14,7 +15,7 @@ namespace Discord
public static string Italics(string text) => $"*{text}*"; public static string Italics(string text) => $"*{text}*";
/// <summary> Returns a markdown-formatted string with underline formatting. </summary> /// <summary> Returns a markdown-formatted string with underline formatting. </summary>
public static string Underline(string text) => $"__{text}__"; public static string Underline(string text) => $"__{text}__";
/// <summary> Returns a markdown-formatted string with strikethrough formatting. </summary>
/// <summary> Returns a markdown-formatted string with strike-through formatting. </summary>
public static string Strikethrough(string text) => $"~~{text}~~"; public static string Strikethrough(string text) => $"~~{text}~~";
/// <summary> Returns a string with spoiler formatting. </summary> /// <summary> Returns a string with spoiler formatting. </summary>
public static string Spoiler(string text) => $"||{text}||"; public static string Spoiler(string text) => $"||{text}||";
@@ -91,5 +92,17 @@ namespace Discord


return $">>> {text}"; return $">>> {text}";
} }

/// <summary>
/// Remove discord supported markdown from text.
/// </summary>
/// <param name="text">The to remove markdown from.</param>
/// <returns>Gets the unformatted text.</returns>
public static string StripMarkDown(string text)
{
//Remove discord supported markdown
var newText = Regex.Replace(text, @"(\*|_|`|~|>|\\)", "");
return newText;
}
} }
} }

+ 0
- 4
src/Discord.Net.Core/Net/ApplicationCommandException.cs View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord.Net namespace Discord.Net
{ {


+ 2
- 2
src/Discord.Net.Core/RequestOptions.cs View File

@@ -16,10 +16,10 @@ namespace Discord
public static RequestOptions Default => new RequestOptions(); public static RequestOptions Default => new RequestOptions();


/// <summary> /// <summary>
/// Gets or sets the maximum time to wait for for this request to complete.
/// Gets or sets the maximum time to wait for this request to complete.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Gets or set the max time, in milliseconds, to wait for for this request to complete. If
/// Gets or set the max time, in milliseconds, to wait for this request to complete. If
/// <c>null</c>, a request will not time out. If a rate limit has been triggered for this request's bucket /// <c>null</c>, a request will not time out. If a rate limit has been triggered for this request's bucket
/// and will not be unpaused in time, this request will fail immediately. /// and will not be unpaused in time, this request will fail immediately.
/// </remarks> /// </remarks>


+ 25
- 5
src/Discord.Net.Core/Utils/UrlValidation.cs View File

@@ -6,16 +6,36 @@ namespace Discord.Utils
{ {
/// <summary> /// <summary>
/// Not full URL validation right now. Just ensures protocol is present and that it's either http or https /// Not full URL validation right now. Just ensures protocol is present and that it's either http or https
/// <see cref="ValidateButton(string)"/> should be used for url buttons.
/// </summary> /// </summary>
/// <param name="url">url to validate before sending to Discord.</param>
/// <param name="url">The URL to validate before sending to Discord.</param>
/// <param name="allowAttachments"><see langword="true"/> to allow the <b>attachment://</b> protocol; otherwise <see langword="false"/>.</param>
/// <exception cref="InvalidOperationException">A URL must include a protocol (http or https).</exception> /// <exception cref="InvalidOperationException">A URL must include a protocol (http or https).</exception>
/// <returns>true if url is valid by our standard, false if null, throws an error upon invalid </returns>
public static bool Validate(string url)
/// <returns>true if URL is valid by our standard, false if null, throws an error upon invalid.</returns>
public static bool Validate(string url, bool allowAttachments = false)
{ {
if (string.IsNullOrEmpty(url)) if (string.IsNullOrEmpty(url))
return false; return false;
if(!(url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || (url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))))
throw new InvalidOperationException($"Url {url} must be include its protocol (either HTTP or HTTPS)");
if (!(url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || url.StartsWith("https://", StringComparison.OrdinalIgnoreCase) || (allowAttachments ? url.StartsWith("attachment://", StringComparison.Ordinal) : false)))
throw new InvalidOperationException($"The url {url} must include a protocol (either {(allowAttachments ? "HTTP, HTTPS, or ATTACHMENT" : "HTTP or HTTPS")})");
return true;
}

/// <summary>
/// Not full URL validation right now. Just Ensures the protocol is either http, https, or discord
/// <see cref="Validate(string)"/> should be used everything other than url buttons.
/// </summary>
/// <param name="url">The URL to validate before sending to discord.</param>
/// <exception cref="InvalidOperationException">A URL must include a protocol (either http, https, or discord).</exception>
/// <returns>true if the URL is valid by our standard, false if null, throws an error upon invalid.</returns>
public static bool ValidateButton(string url)
{
if (string.IsNullOrEmpty(url))
return false;
if (!(url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
url.StartsWith("https://", StringComparison.OrdinalIgnoreCase) ||
url.StartsWith("discord://", StringComparison.OrdinalIgnoreCase)))
throw new InvalidOperationException($"The url {url} must include a protocol (either HTTP, HTTPS, or DISCORD)");
return true; return true;
} }
} }


+ 0
- 1
src/Discord.Net.Examples/Core/Entities/Channels/IMessageChannel.Examples.cs View File

@@ -108,7 +108,6 @@ namespace Discord.Net.Examples.Core.Entities.Channels
using (channel.EnterTypingState()) await LongRunningAsync(); using (channel.EnterTypingState()) await LongRunningAsync();


#endregion #endregion

} }
} }
} }

+ 1
- 1
src/Discord.Net.Examples/Discord.Net.Examples.csproj View File

@@ -15,7 +15,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" /> <ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" />
<ProjectReference Include="..\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" /> <ProjectReference Include="..\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" />
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
<PackageReference Include="JetBrains.Annotations" Version="2021.2.0" />
</ItemGroup> </ItemGroup>


</Project> </Project>

+ 2
- 1
src/Discord.Net.Providers.WS4Net/Discord.Net.Providers.WS4Net.csproj View File

@@ -3,8 +3,9 @@
<PropertyGroup> <PropertyGroup>
<AssemblyName>Discord.Net.Providers.WS4Net</AssemblyName> <AssemblyName>Discord.Net.Providers.WS4Net</AssemblyName>
<RootNamespace>Discord.Providers.WS4Net</RootNamespace> <RootNamespace>Discord.Providers.WS4Net</RootNamespace>
<Description>An optional WebSocket client provider for Discord.Net using WebSocket4Net</Description>
<Description>An optional WebSocket client provider for Discord.Net Labs using WebSocket4Net</Description>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<PackageId>Discord.Net.Labs.Providers.WS4Net</PackageId>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" /> <ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" />


+ 1
- 6
src/Discord.Net.Rest/API/Common/ActionRowComponent.cs View File

@@ -1,10 +1,5 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord.API namespace Discord.API
{ {
@@ -26,7 +21,7 @@ namespace Discord.API
{ {
ComponentType.Button => new ButtonComponent(x as Discord.ButtonComponent), ComponentType.Button => new ButtonComponent(x as Discord.ButtonComponent),
ComponentType.SelectMenu => new SelectMenuComponent(x as Discord.SelectMenuComponent), ComponentType.SelectMenu => new SelectMenuComponent(x as Discord.SelectMenuComponent),
_ => null,
_ => null
}; };
}).ToArray(); }).ToArray();
} }


+ 0
- 5
src/Discord.Net.Rest/API/Common/ApplicationCommand.cs View File

@@ -1,9 +1,4 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord.API namespace Discord.API
{ {


+ 0
- 2
src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionData.cs View File

@@ -1,5 +1,4 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Collections.Generic;


namespace Discord.API namespace Discord.API
{ {
@@ -19,6 +18,5 @@ namespace Discord.API


[JsonProperty("type")] [JsonProperty("type")]
public ApplicationCommandType Type { get; set; } public ApplicationCommandType Type { get; set; }

} }
} }

+ 0
- 1
src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionDataOption.cs View File

@@ -1,5 +1,4 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Collections.Generic;


namespace Discord.API namespace Discord.API
{ {


+ 22
- 31
src/Discord.Net.Rest/API/Common/ApplicationCommandOption.cs View File

@@ -1,9 +1,5 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord.API namespace Discord.API
{ {
@@ -33,11 +29,14 @@ namespace Discord.API
[JsonProperty("autocomplete")] [JsonProperty("autocomplete")]
public Optional<bool> Autocomplete { get; set; } public Optional<bool> Autocomplete { get; set; }


[JsonProperty("channel_types")]
public Optional<ChannelType[]> ChannelTypes { get; set; }

public ApplicationCommandOption() { } public ApplicationCommandOption() { }


public ApplicationCommandOption(IApplicationCommandOption cmd) public ApplicationCommandOption(IApplicationCommandOption cmd)
{ {
Choices = cmd.Choices.Select(x => new ApplicationCommandOptionChoice()
Choices = cmd.Choices.Select(x => new ApplicationCommandOptionChoice
{ {
Name = x.Name, Name = x.Name,
Value = x.Value Value = x.Value
@@ -45,38 +44,30 @@ namespace Discord.API


Options = cmd.Options.Select(x => new ApplicationCommandOption(x)).ToArray(); Options = cmd.Options.Select(x => new ApplicationCommandOption(x)).ToArray();


Required = cmd.IsRequired.HasValue
? cmd.IsRequired.Value
: Optional<bool>.Unspecified;
Default = cmd.IsDefault.HasValue
? cmd.IsDefault.Value
: Optional<bool>.Unspecified;
ChannelTypes = cmd.ChannelTypes.ToArray();

Required = cmd.IsRequired ?? Optional<bool>.Unspecified;
Default = cmd.IsDefault ?? Optional<bool>.Unspecified;


Name = cmd.Name; Name = cmd.Name;
Type = cmd.Type; Type = cmd.Type;
Description = cmd.Description; Description = cmd.Description;
} }
public ApplicationCommandOption(Discord.ApplicationCommandOptionProperties option)
public ApplicationCommandOption(ApplicationCommandOptionProperties option)
{ {
Choices = option.Choices != null
? option.Choices.Select(x => new ApplicationCommandOptionChoice()
{
Name = x.Name,
Value = x.Value
}).ToArray()
: Optional<ApplicationCommandOptionChoice[]>.Unspecified;

Options = option.Options != null
? option.Options.Select(x => new ApplicationCommandOption(x)).ToArray()
: Optional<ApplicationCommandOption[]>.Unspecified;

Required = option.IsRequired.HasValue
? option.IsRequired.Value
: Optional<bool>.Unspecified;

Default = option.IsDefault.HasValue
? option.IsDefault.Value
: Optional<bool>.Unspecified;
Choices = option.Choices?.Select(x => new ApplicationCommandOptionChoice
{
Name = x.Name,
Value = x.Value
}).ToArray() ?? Optional<ApplicationCommandOptionChoice[]>.Unspecified;

Options = option.Options?.Select(x => new ApplicationCommandOption(x)).ToArray() ?? Optional<ApplicationCommandOption[]>.Unspecified;

Required = option.IsRequired ?? Optional<bool>.Unspecified;

Default = option.IsDefault ?? Optional<bool>.Unspecified;

ChannelTypes = option.ChannelTypes?.ToArray() ?? Optional<ChannelType[]>.Unspecified;


Name = option.Name; Name = option.Name;
Type = option.Type; Type = option.Type;


+ 0
- 5
src/Discord.Net.Rest/API/Common/ApplicationCommandOptionChoice.cs View File

@@ -1,9 +1,4 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord.API namespace Discord.API
{ {


+ 0
- 5
src/Discord.Net.Rest/API/Common/ApplicationCommandPermissions.cs View File

@@ -1,9 +1,4 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Discord.API namespace Discord.API
{ {


+ 2
- 0
src/Discord.Net.Rest/API/Common/Attachment.cs View File

@@ -18,5 +18,7 @@ namespace Discord.API
public Optional<int> Height { get; set; } public Optional<int> Height { get; set; }
[JsonProperty("width")] [JsonProperty("width")]
public Optional<int> Width { get; set; } public Optional<int> Width { get; set; }
[JsonProperty("ephemeral")]
public Optional<bool> Ephemeral { get; set; }
} }
} }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save