commitpull/988/headdece19d895
Merge:fdaa689a
e764dafe
Author: Still Hsu <341464@gmail.com> Date: Mon May 21 11:47:47 2018 +0800 Merge branch 'dev' into docs/faq-n-patches-offline commite764dafe08
Author: Quahu <quahuu@gmail.com> Date: Sun May 13 15:34:40 2018 +0200 Add ViewChannel to Voice channel permissions (#1059) Previously, Voice channels did not have ViewChannel in their "all" permissions commit32fc2df21b
Author: Alex Gravely <tcbskater@hotmail.com> Date: Sat May 12 20:47:44 2018 -0400 Remove unused field in EmbedFieldBuilder. (#1018) commit39dffe8585
Author: Finite Reality <FiniteReality@users.noreply.github.com> Date: Sun May 13 01:46:07 2018 +0100 Audit Logs implementation (#1055) * Copy audit logs impl from old branch and clean up I suck at using git, so I'm gonna use brute force. * Remove unnecessary TODOs Category channels do not provide any new information, and the other I forgot to remove beforehand * Add invite update data, clean up after feedback * Remove TODOs, add WebhookType enum for future use WebhookType is a future-use type, as currently audit logs are the only thing which may return it. commitfdaa689ae8
Author: Still Hsu <341464@gmail.com> Date: Wed May 9 06:04:59 2018 +0800 Add explanation for RunMode commitea82c2537e
Author: Still Hsu <341464@gmail.com> Date: Tue May 8 16:30:48 2018 +0800 Initial proofread of the articles commit124f1a267c
Merge:25557218
97c89310
Author: Still Hsu <341464@gmail.com> Date: Tue May 8 05:02:01 2018 +0800 Merge branch 'dev' into docs/faq-n-patches-offline commit97c893107b
Author: Still Hsu <341464@gmail.com> Date: Mon May 7 06:22:49 2018 +0800 Implement GetBanAsync (#1056) commit25557218db
Author: Still Hsu <341464@gmail.com> Date: Sun May 6 16:11:19 2018 +0800 Add details to SpotifyGame commitc7b236ddf5
Author: Still Hsu <341464@gmail.com> Date: Sun May 6 15:58:23 2018 +0800 Add more IGuild docs commit1bb06cc37b
Author: Still Hsu <341464@gmail.com> Date: Sun May 6 15:40:31 2018 +0800 Replace all langword placements with code block commitac47d84ea7
Author: Still Hsu <341464@gmail.com> Date: Sun May 6 15:22:17 2018 +0800 Replace langword null to code block null instead - Because DocFX sucks at rendering langword commit0b15bbc54d
Author: Still Hsu <341464@gmail.com> Date: Sun May 6 15:20:34 2018 +0800 Add XML docs commit65d4e4360e
Author: Still Hsu <341464@gmail.com> Date: Sun May 6 06:57:53 2018 +0800 Add BaseSocketClient docs commit8f64c04599
Author: Still Hsu <341464@gmail.com> Date: Sun May 6 06:37:55 2018 +0800 Replace note block commitd8bb9e7aaa
Author: Still Hsu <341464@gmail.com> Date: Sun May 6 06:31:50 2018 +0800 Add warning for bulk-delete endpoint commitadae5ffc9e
Author: Still Hsu <341464@gmail.com> Date: Sun May 6 06:07:28 2018 +0800 Fix missing Username prop commit3e591972ca
Author: Still Hsu <341464@gmail.com> Date: Sun May 6 06:01:34 2018 +0800 Add properties examples to overwrite commit0ad66f6765
Author: Still Hsu <341464@gmail.com> Date: Sun May 6 04:55:15 2018 +0800 Fix minor consistencies & redundant impl commit124efdf7e6
Author: Still Hsu <341464@gmail.com> Date: Sun May 6 04:40:14 2018 +0800 XML Docs commit3aa5d363de
Author: Still Hsu <341464@gmail.com> Date: Sat May 5 18:22:46 2018 +0800 Add 'last modified' plugin Source: https://github.com/Still34/DocFx.Plugin.LastModified Licensed under MIT License commit2014870dc0
Author: Still Hsu <341464@gmail.com> Date: Sat May 5 15:57:40 2018 +0800 Fix letter-casing for files commitf27d659ebe
Author: Still Hsu <341464@gmail.com> Date: Sat May 5 15:50:00 2018 +0800 Document exposed TypeReaders commit5a824a5695
Author: Still Hsu <341464@gmail.com> Date: Sat May 5 15:44:15 2018 +0800 Add missing exceptions commitc2de0c055f
Author: Still Hsu <341464@gmail.com> Date: Sat May 5 15:40:16 2018 +0800 Fix seealso for preconditions and add missing descriptions commit3a7d7ee955
Author: Still Hsu <341464@gmail.com> Date: Sat May 5 15:36:22 2018 +0800 Minor fixes in documentations + Fix unescaped '<' + Fix typo commit45839bd982
Author: Still Hsu <341464@gmail.com> Date: Sat May 5 15:29:47 2018 +0800 Add XML Docs commit9e6254600c
Merge:aea06788
bb4bb138
Author: Still Hsu <341464@gmail.com> Date: Sat May 5 14:48:13 2018 +0800 Merge branch 'dev' into docs/faq-n-patches-offline commitaea067884c
Merge:27dc4831
9ddd7090
Author: Still Hsu <341464@gmail.com> Date: Sat May 5 13:51:07 2018 +0800 Merge branch 'docs/faq-n-patches-offline' of https://github.com/Still34/Discord.Net into docs/faq-n-patches-offline commit27dc4831e8
Author: Still Hsu <341464@gmail.com> Date: Sat May 5 13:50:27 2018 +0800 Add XML Docs commitbaa8beb382
Author: Still Hsu <341464@gmail.com> Date: Sat May 5 13:49:42 2018 +0800 Add XML Docs commit089f97a010
Author: Still Hsu <341464@gmail.com> Date: Sat May 5 13:43:04 2018 +0800 Add details regarding userbot support commitbb4bb13846
Author: Finite Reality <FiniteReality@users.noreply.github.com> Date: Fri May 4 11:42:54 2018 +0100 Fix issues with #984, remove extraneous whitespace (#1051) - Removed unnecessary parameter in SocketVoiceServer - Moved SocketVoiceServer into Entities/Voice - Fixed a bug where trying to download the cached guild would throw - Fixed a potential bug where Discord might not give us a port when connecting to voice commit9ddd70906a
Merge:f197174f
7cfed7ff
Author: Still Hsu <341464@gmail.com> Date: Fri May 4 09:37:04 2018 +0800 Merge branch 'dev' into docs/faq-n-patches-offline commitf197174fcc
Author: Still Hsu <341464@gmail.com> Date: Fri May 4 09:36:53 2018 +0800 Fix embed docs consistency commit7cfed7ff67
Author: Alex Gravely <tcbskater@hotmail.com> Date: Thu May 3 21:30:13 2018 -0400 Fix nullref when passing null to GetShardIdFor. (#1049) commite775853b1b
Author: Luke <dev@crimsonxv.pro> Date: Fri May 4 02:29:51 2018 +0100 Expose VoiceServerUpdate events (#984) * Expose VoiceServerUpdate events * Amend based on feedback * Move this out of guild entity * Fix namespace issue * Adjust based on feedback #2 * Use cacheable instead * Change based on feedback commit157acc4695
Author: Still Hsu <341464@gmail.com> Date: Thu May 3 23:03:35 2018 +0800 Add tag examples commit57ea571a81
Author: Still Hsu <341464@gmail.com> Date: Thu May 3 22:48:33 2018 +0800 Fix sample link & add missing pictures commit6769c37ad7
Author: Still Hsu <341464@gmail.com> Date: Thu May 3 22:39:26 2018 +0800 Compress some assets & add OAuth2 URL generator
@@ -1,7 +1,5 @@ | |||||
--- | --- | ||||
uid: Discord.Commands.PreconditionAttribute | uid: Discord.Commands.PreconditionAttribute | ||||
seealso: | |||||
- linkId: Discord.Commands.ParameterPreconditionAttribute | |||||
remarks: *content | remarks: *content | ||||
--- | --- | ||||
@@ -12,8 +10,6 @@ method-level for a command. | |||||
--- | --- | ||||
uid: Discord.Commands.ParameterPreconditionAttribute | uid: Discord.Commands.ParameterPreconditionAttribute | ||||
seealso: | |||||
- linkId: Discord.Commands.PreconditionAttribute | |||||
remarks: *content | remarks: *content | ||||
--- | --- | ||||
@@ -31,11 +27,11 @@ The following example creates a precondition to see if the user has | |||||
sufficient role required to access the command. | sufficient role required to access the command. | ||||
```cs | ```cs | ||||
public class RequireRoleAtribute : PreconditionAttribute | |||||
public class RequireRoleAttribute : PreconditionAttribute | |||||
{ | { | ||||
private readonly ulong _roleId; | private readonly ulong _roleId; | ||||
public RequireRoleAtribute(ulong roleId) | |||||
public RequireRoleAttribute(ulong roleId) | |||||
{ | { | ||||
_roleId = roleId; | _roleId = roleId; | ||||
} | } | ||||
@@ -0,0 +1,174 @@ | |||||
--- | |||||
uid: Discord.GuildChannelProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IGuildChannel.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var channel = _client.GetChannel(id) as IGuildChannel; | |||||
if (channel == null) return; | |||||
await channel.ModifyAsync(x => | |||||
{ | |||||
x.Name = "new-name"; | |||||
x.Position = channel.Position - 1; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.TextChannelProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.ITextChannel.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var channel = _client.GetChannel(id) as ITextChannel; | |||||
if (channel == null) return; | |||||
await channel.ModifyAsync(x => | |||||
{ | |||||
x.Name = "cool-guys-only"; | |||||
x.Topic = "This channel is only for cool guys and adults!!!"; | |||||
x.Position = channel.Position - 1; | |||||
x.IsNsfw = true; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.VoiceChannelProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IVoiceChannel.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var channel = _client.GetChannel(id) as IVoiceChannel; | |||||
if (channel == null) return; | |||||
await channel.ModifyAsync(x => | |||||
{ | |||||
x.UserLimit = 5; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.EmoteProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IGuild.ModifyEmoteAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
await guild.ModifyEmoteAsync(x => | |||||
{ | |||||
x.Name = "blobo"; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.MessageProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IUserMessage.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var message = await channel.SendMessageAsync("boo"); | |||||
await Task.Delay(TimeSpan.FromSeconds(1)); | |||||
await message.ModifyAsync(x => x.Content = "boi"); | |||||
``` | |||||
--- | |||||
uid: Discord.GuildProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IGuild.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var guild = _client.GetGuild(id); | |||||
if (guild == null) return; | |||||
await guild.ModifyAsync(x => | |||||
{ | |||||
x.Name = "VERY Fast Discord Running at Incredible Hihg Speed"; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.RoleProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IRole.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var role = guild.GetRole(id); | |||||
if (role == null) return; | |||||
await role.ModifyAsync(x => | |||||
{ | |||||
x.Name = "cool boi"; | |||||
x.Color = Color.Gold; | |||||
x.Hoist = true; | |||||
x.Mentionable = true; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.GuildUserProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IGuildUser.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
var user = guild.GetUser(id); | |||||
if (user == null) return; | |||||
await user.ModifyAsync(x => | |||||
{ | |||||
x.Nickname = "I need healing"; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.SelfUserProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.ISelfUser.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
await selfUser.ModifyAsync(x => | |||||
{ | |||||
x.Username = "Mercy"; | |||||
}); | |||||
``` | |||||
--- | |||||
uid: Discord.WebhookProperties | |||||
example: [*content] | |||||
--- | |||||
The following example uses @Discord.IWebhook.ModifyAsync* to | |||||
apply changes specified in the properties, | |||||
```cs | |||||
await webhook.ModifyAsync(x => | |||||
{ | |||||
x.Name = "very fast fox"; | |||||
x.ChannelId = newChannelId; | |||||
}); | |||||
``` |
@@ -35,9 +35,10 @@ | |||||
"dest": "_site", | "dest": "_site", | ||||
"template": [ | "template": [ | ||||
"default", | "default", | ||||
"_template/light-dark-theme" | |||||
"_template/light-dark-theme", | |||||
"_template/lastmodified" | |||||
], | ], | ||||
"postProcessors": [ "ExtractSearchIndex" ], | |||||
"postProcessors": [ "ExtractSearchIndex", "LastModifiedPostProcessor" ], | |||||
"overwrite": "_overwrites/**/**.md", | "overwrite": "_overwrites/**/**.md", | ||||
"globalMetadata": { | "globalMetadata": { | ||||
"_appTitle": "Discord.Net Documentation", | "_appTitle": "Discord.Net Documentation", | ||||
@@ -8,7 +8,7 @@ title: Questions about Basic Operations | |||||
## How should I safely check a type? | ## How should I safely check a type? | ||||
> [!WARNING] | > [!WARNING] | ||||
> Direct casting (e.g. `(Type)type`) is **the least recommended** | |||||
> Direct casting (e.g., `(Type)type`) is **the least recommended** | |||||
> way of casting, as it *can* throw an [InvalidCastException] | > way of casting, as it *can* throw an [InvalidCastException] | ||||
> when the object isn't the desired type. | > when the object isn't the desired type. | ||||
> | > | ||||
@@ -28,9 +28,9 @@ A good and safe casting example: | |||||
## How do I send a message? | ## How do I send a message? | ||||
> [!TIP] | > [!TIP] | ||||
> The [GetChannel] method by default returns an [IChannel]. | |||||
> This means channels such as [IVoiceChannel], [ICategoryChannel] | |||||
> can be returned. This is why that you cannot send message | |||||
> The [GetChannel] method by default returns an [IChannel], allowing | |||||
> channel types such as [IVoiceChannel], [ICategoryChannel] | |||||
> to be returned; consequently, you cannot send a message | |||||
> to channels like those. | > to channels like those. | ||||
Any implementation of [IMessageChannel] has a [SendMessageAsync] | Any implementation of [IMessageChannel] has a [SendMessageAsync] | ||||
@@ -8,11 +8,12 @@ title: Basic Questions about Client | |||||
## My client keeps returning 401 upon logging in! | ## My client keeps returning 401 upon logging in! | ||||
> [!WARNING] | > [!WARNING] | ||||
> Userbot/selfbot (logging in with a user token) is not | |||||
> officially supported with this library. | |||||
> Userbot/selfbot (logging in with a user token) is no | |||||
> longer supported with this library starting from 2.0, as | |||||
> logging in under a user account may result in account termination. | |||||
> | > | ||||
> Logging in under a user account may result in account | |||||
> termination! | |||||
> For more information, see issue [827] & [958], as well as the official | |||||
> [Discord API Terms of Service]. | |||||
There are few possible reasons why this may occur. | There are few possible reasons why this may occur. | ||||
@@ -20,20 +21,23 @@ There are few possible reasons why this may occur. | |||||
bot account created from the Discord Developer portal, you should | bot account created from the Discord Developer portal, you should | ||||
be using `TokenType.Bot`. | be using `TokenType.Bot`. | ||||
2. You are not using the correct login credentials. Please keep in | 2. You are not using the correct login credentials. Please keep in | ||||
mind that tokens is different from a *client secret*. | |||||
mind that a token is **different** from a *client secret*. | |||||
[TokenType]: xref:Discord.TokenType | [TokenType]: xref:Discord.TokenType | ||||
[827]: https://github.com/RogueException/Discord.Net/issues/827 | |||||
[958]: https://github.com/RogueException/Discord.Net/issues/958 | |||||
[Discord API Terms of Service]: https://discordapp.com/developers/docs/legal | |||||
## How do I do X, Y, Z when my bot connects/logs on? Why do I get a `NullReferenceException` upon calling any client methods after connect? | ## How do I do X, Y, Z when my bot connects/logs on? Why do I get a `NullReferenceException` upon calling any client methods after connect? | ||||
Your bot should **not** attempt to interact in any way with | Your bot should **not** attempt to interact in any way with | ||||
guilds/servers until the [Ready] event fires. When the bot | guilds/servers until the [Ready] event fires. When the bot | ||||
connects, it first has to download guild information from | connects, it first has to download guild information from | ||||
Discord in order for you to get access to any server | |||||
Discord for you to get access to any server | |||||
information; the client is not ready at this point. | information; the client is not ready at this point. | ||||
Technically, the [GuildAvailable] event fires once the data for a | Technically, the [GuildAvailable] event fires once the data for a | ||||
particular guild has downloaded; however, it's best to wait for all | |||||
particular guild has downloaded; however, it is best to wait for all | |||||
guilds to be downloaded. Once all downloads are complete, the [Ready] | guilds to be downloaded. Once all downloads are complete, the [Ready] | ||||
event is triggered, then you can proceed to do whatever you like. | event is triggered, then you can proceed to do whatever you like. | ||||
@@ -42,7 +46,7 @@ event is triggered, then you can proceed to do whatever you like. | |||||
## How do I get a message's previous content when that message is edited? | ## How do I get a message's previous content when that message is edited? | ||||
If you need to do anything with messages (e.g. checking Reactions, | |||||
If you need to do anything with messages (e.g., checking Reactions, | |||||
checking the content of edited/deleted messages), you must set the | checking the content of edited/deleted messages), you must set the | ||||
[MessageCacheSize] in your [DiscordSocketConfig] settings in order to | [MessageCacheSize] in your [DiscordSocketConfig] settings in order to | ||||
use the cached message entity. Read more about it [here](xref:Guides.Concepts.Events#cacheable). | use the cached message entity. Read more about it [here](xref:Guides.Concepts.Events#cacheable). | ||||
@@ -8,25 +8,27 @@ title: Beginner Questions / How to Get Started | |||||
## How do I add my bot to my server/guild? | ## How do I add my bot to my server/guild? | ||||
You can do so by using the [permission calculator] provided | You can do so by using the [permission calculator] provided | ||||
by FiniteReality. | |||||
This tool allows you to set the permissions that the bot will be | |||||
added with, and invite the bot into your guild. With this method, | |||||
bots will also be assigned their own special roles that normal users | |||||
cannot use; this is what we call a `Managed` role, and this is a much | |||||
safer method of permission management than to create a role that any | |||||
users can be assigned to. | |||||
by [FiniteReality]. | |||||
This tool allows you to set permissions that the bot will be assigned | |||||
with, and invite the bot into your guild. With this method, bots will | |||||
also be assigned a unique role that a regular user cannot use; this | |||||
is what we call a `Managed` role. Because you cannot assign this | |||||
role to any other users, it is much safer than creating a single | |||||
role which, intentionally or not, can be applied to other users | |||||
to escalate their privilege. | |||||
[FiniteReality]: https://github.com/FiniteReality/permissions-calculator | |||||
[permission calculator]: https://finitereality.github.io/permissions-calculator | [permission calculator]: https://finitereality.github.io/permissions-calculator | ||||
## What is a token? | ## What is a token? | ||||
A token is a credential used to log into an account. This information | A token is a credential used to log into an account. This information | ||||
should be kept **private** and for your eyes only. Anyone with your | should be kept **private** and for your eyes only. Anyone with your | ||||
token can log into your account. This applies to both user and bot | |||||
accounts. That also means that you should never ever hardcode your | |||||
token or add it into source control, as your identity may be stolen | |||||
by scrape bots on the internet that scours through constantly to | |||||
obtain a token. | |||||
token can log into your account. This risk applies to both user | |||||
and bot accounts. That also means that you should **never** hardcode | |||||
your token or add it into source control, as your identity may be | |||||
stolen by scrape bots on the internet that scours through | |||||
constantly to obtain a token. | |||||
## What is a client/user/object ID? | ## What is a client/user/object ID? | ||||
@@ -5,37 +5,35 @@ title: Questions about Commands | |||||
# Command-related Questions | # Command-related Questions | ||||
## How can I restrict some of my commands so only certain users can execute them? | |||||
## How can I restrict some of my commands so only specific users can execute them? | |||||
Based on how you want to implement the restrictions, you can use the | Based on how you want to implement the restrictions, you can use the | ||||
built-in [RequireUserPermission] precondition, which allows you to | built-in [RequireUserPermission] precondition, which allows you to | ||||
restrict the command based on the user's current permissions in the | restrict the command based on the user's current permissions in the | ||||
guild or channel (*e.g. `GuildPermission.Administrator`, | |||||
`ChannelPermission.ManageMessages` etc.*). | |||||
guild or channel (*e.g., `GuildPermission.Administrator`, | |||||
`ChannelPermission.ManageMessages`*). | |||||
If, however, you wish to restrict the commands based on the user's | If, however, you wish to restrict the commands based on the user's | ||||
role, you can either create your own custom precondition or use | |||||
role, you can either create your custom precondition or use | |||||
Joe4evr's [Preconditions Addons] that provides a few custom | Joe4evr's [Preconditions Addons] that provides a few custom | ||||
preconditions that aren't provided in the stock library. | preconditions that aren't provided in the stock library. | ||||
Its source can also be used as an example for creating your own | |||||
Its source can also be used as an example for creating your | |||||
custom preconditions. | custom preconditions. | ||||
[RequireUserPermission]: xref:Discord.Commands.RequireUserPermissionAttribute | [RequireUserPermission]: xref:Discord.Commands.RequireUserPermissionAttribute | ||||
[Preconditions Addons]: https://github.com/Joe4evr/Discord.Addons/tree/master/src/Discord.Addons.Preconditions | [Preconditions Addons]: https://github.com/Joe4evr/Discord.Addons/tree/master/src/Discord.Addons.Preconditions | ||||
## I'm getting an error about `Assembly#GetEntryAssembly`. | |||||
## Why am I getting an error about `Assembly.GetEntryAssembly`? | |||||
You may be confusing [CommandService#AddModulesAsync] with | |||||
[CommandService#AddModuleAsync]. The former is used to add modules | |||||
via the assembly, while the latter is used to add a single module. | |||||
[CommandService#AddModulesAsync]: xref:Discord.Commands.CommandService.AddModulesAsync* | |||||
[CommandService#AddModuleAsync]: xref:Discord.Commands.CommandService.AddModuleAsync* | |||||
You may be confusing @Discord.Commands.CommandService.AddModulesAsync* | |||||
with @Discord.Commands.CommandService.AddModuleAsync*. The former | |||||
is used to add modules via the assembly, while the latter is used to | |||||
add a single module. | |||||
## What does [Remainder] do in the command signature? | ## What does [Remainder] do in the command signature? | ||||
The [RemainderAttribute] leaves the string unparsed, meaning you | The [RemainderAttribute] leaves the string unparsed, meaning you | ||||
don't have to add quotes around the text for the text to be | |||||
do not have to add quotes around the text for the text to be | |||||
recognized as a single object. Please note that if your method has | recognized as a single object. Please note that if your method has | ||||
multiple parameters, the remainder attribute can only be applied to | multiple parameters, the remainder attribute can only be applied to | ||||
the last parameter. | the last parameter. | ||||
@@ -47,13 +45,14 @@ the last parameter. | |||||
## What is a service? Why does my module not hold any data after execution? | ## What is a service? Why does my module not hold any data after execution? | ||||
In Discord.Net, modules are created similarly to ASP.NET, meaning | In Discord.Net, modules are created similarly to ASP.NET, meaning | ||||
that they have a transient nature. This means that they are spawned | |||||
every time when a request is received, and are killed from memory | |||||
when the execution finishes. This is why you cannot store persistent | |||||
data inside a module. To workaround this, consider using a service. | |||||
Service is often used to hold data externally, so that they will | |||||
persist throughout execution. Think of it like a chest that holds | |||||
that they have a transient nature; modules are spawned whenever a | |||||
request is received, and are killed from memory when the execution | |||||
finishes. In other words, you cannot store persistent | |||||
data inside a module. Consider using a service if you wish to | |||||
workaround this. | |||||
Service is often used to hold data externally so that they persist | |||||
throughout execution. Think of it like a chest that holds | |||||
whatever you throw at it that won't be affected by anything unless | whatever you throw at it that won't be affected by anything unless | ||||
you want it to. Note that you should also learn Microsoft's | you want it to. Note that you should also learn Microsoft's | ||||
implementation of [Dependency Injection] \([video]) before proceeding, | implementation of [Dependency Injection] \([video]) before proceeding, | ||||
@@ -66,25 +65,47 @@ A brief example of service and dependency injection can be seen below. | |||||
[Dependency Injection]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection | [Dependency Injection]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection | ||||
[video]: https://www.youtube.com/watch?v=QtDTfn8YxXg | [video]: https://www.youtube.com/watch?v=QtDTfn8YxXg | ||||
## I have a long-running Task in my command, and Discord.Net keeps saying that a `MessageReceived` handler is blocking the gateway. What gives? | |||||
## Discord.Net keeps saying that a `MessageReceived` handler is blocking the gateway, what should I do? | |||||
By default, the library warns the user about any long-running event | |||||
handler that persists for **more than 3 seconds**. Any event | |||||
handlers that are run on the same thread as the gateway task, the task | |||||
in charge of keeping the connection alive, may block the processing of | |||||
heartbeat, and thus terminating the connection. | |||||
In this case, the library detects that a `MessageReceived` | |||||
event handler is blocking the gateway thread. This warning is | |||||
typically associated with the command handler as it listens for that | |||||
particular event. If the command handler is blocking the thread, then | |||||
this **might** mean that you have a long-running command. | |||||
By default, all commands are executed on the same thread as the | |||||
gateway task, which is responsible for keeping the connection from | |||||
your client to Discord alive. When you execute a command, | |||||
this blocks the gateway from communicating for as long as the command | |||||
task is being executed. The library will warn you about any long | |||||
running event handler (in this case, the command handler) that | |||||
persists for **more than 3 seconds**. | |||||
> [!NOTE] | |||||
> In rare cases, runtime errors can also cause blockage, usually | |||||
> associated with Mono, which is not supported by this library. | |||||
To resolve this, the library has designed a flag called [RunMode]. | |||||
To prevent a long-running command from blocking the gateway | |||||
thread, a flag called [RunMode] is explicitly designed to resolve | |||||
this issue. | |||||
There are 2 main `RunMode`s. | There are 2 main `RunMode`s. | ||||
1. `RunMode.Sync` (default) | |||||
1. `RunMode.Sync` | |||||
2. `RunMode.Async` | 2. `RunMode.Async` | ||||
`Sync` is the default behavior and makes the command to be run on the | |||||
same thread as the gateway one. `Async` will spin the task off to a | |||||
different thread from the gateway one. | |||||
> [!IMPORTANT] | |||||
> While specifying `RunMode.Async` allows the command to be spun off | |||||
> to a different thread, keep in mind that by doing so, there will be | |||||
> **potentially unwanted consequences**. Before applying this flag, | |||||
> please consider whether it is necessary to do so. | |||||
> | |||||
> Further details regarding `RunMode.Async` can be found below. | |||||
You can set the `RunMode` either by specifying it individually via | You can set the `RunMode` either by specifying it individually via | ||||
the `CommandAttribute`, or by setting the global default with | |||||
the `CommandAttribute` or by setting the global default with | |||||
the [DefaultRunMode] flag under `CommandServiceConfig`. | the [DefaultRunMode] flag under `CommandServiceConfig`. | ||||
# [CommandAttribute](#tab/cmdattrib) | # [CommandAttribute](#tab/cmdattrib) | ||||
@@ -99,15 +120,6 @@ the [DefaultRunMode] flag under `CommandServiceConfig`. | |||||
*** | *** | ||||
> [!IMPORTANT] | |||||
> While specifying `RunMode.Async` allows the command to be spun off | |||||
> to a different thread instead of the gateway thread, | |||||
> keep in mind that there will be **potential consequences** | |||||
> by doing so. Before applying this flag, please | |||||
> consider whether it is necessary to do so. | |||||
> | |||||
> Further details regarding `RunMode.Async` can be found below. | |||||
[RunMode]: xref:Discord.Commands.RunMode | [RunMode]: xref:Discord.Commands.RunMode | ||||
[CommandAttribute]: xref:Discord.Commands.CommandAttribute | [CommandAttribute]: xref:Discord.Commands.CommandAttribute | ||||
[DefaultRunMode]: xref:Discord.Commands.CommandServiceConfig.DefaultRunMode | [DefaultRunMode]: xref:Discord.Commands.CommandServiceConfig.DefaultRunMode | ||||
@@ -115,16 +127,15 @@ the [DefaultRunMode] flag under `CommandServiceConfig`. | |||||
## How does `RunMode.Async` work, and why is Discord.Net *not* using it by default? | ## How does `RunMode.Async` work, and why is Discord.Net *not* using it by default? | ||||
`RunMode.Async` works by spawning a new `Task` with an unawaited | `RunMode.Async` works by spawning a new `Task` with an unawaited | ||||
[Task.Run], essentially making `ExecuteAsyncInternalAsync`, the task | |||||
that is used to invoke the command task, to be finished on a | |||||
different thread. This means that [ExecuteAsync] will be forced to | |||||
return a successful [ExecuteResult] regardless of the actual | |||||
execution result. | |||||
[Task.Run], essentially making the task that is used to invoke the | |||||
command task to be finished on a different thread. This design means | |||||
that [ExecuteAsync] will be forced to return a successful | |||||
[ExecuteResult] regardless of the actual execution result. | |||||
The following are the known caveats with `RunMode.Async`, | The following are the known caveats with `RunMode.Async`, | ||||
1. You can potentially introduce race condition. | |||||
2. Unnecessary overhead caused by [async state machine]. | |||||
1. You can potentially introduce a race condition. | |||||
2. Unnecessary overhead caused by the [async state machine]. | |||||
3. [ExecuteAsync] will immediately return [ExecuteResult] instead of | 3. [ExecuteAsync] will immediately return [ExecuteResult] instead of | ||||
other result types (this is particularly important for those who wish | other result types (this is particularly important for those who wish | ||||
to utilize [RuntimeResult] in 2.0). | to utilize [RuntimeResult] in 2.0). | ||||
@@ -137,7 +148,7 @@ For #3, in Discord.Net 2.0, the library introduces a new event called | |||||
**successfully executed**. This event will be raised regardless of | **successfully executed**. This event will be raised regardless of | ||||
the `RunMode` type and will return the appropriate execution result. | the `RunMode` type and will return the appropriate execution result. | ||||
For #4, exceptions are caught in [CommandService#Log] event under | |||||
For #4, exceptions are caught in [CommandService.Log] event under | |||||
[LogMessage.Exception] as [CommandException]. | [LogMessage.Exception] as [CommandException]. | ||||
[Task.Run]: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run | [Task.Run]: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run | ||||
@@ -146,6 +157,6 @@ For #4, exceptions are caught in [CommandService#Log] event under | |||||
[ExecuteResult]: xref:Discord.Commands.ExecuteResult | [ExecuteResult]: xref:Discord.Commands.ExecuteResult | ||||
[RuntimeResult]: xref:Discord.Commands.RuntimeResult | [RuntimeResult]: xref:Discord.Commands.RuntimeResult | ||||
[CommandExecuted]: xref:Discord.Commands.CommandService.CommandExecuted | [CommandExecuted]: xref:Discord.Commands.CommandService.CommandExecuted | ||||
[CommandService#Log]: xref:Discord.Commands.CommandService.Log | |||||
[CommandService.Log]: xref:Discord.Commands.CommandService.Log | |||||
[LogMessage.Exception]: xref:Discord.LogMessage.Exception* | [LogMessage.Exception]: xref:Discord.LogMessage.Exception* | ||||
[CommandException]: xref:Discord.Commands.CommandException | [CommandException]: xref:Discord.Commands.CommandException |
@@ -16,5 +16,5 @@ public Task EchoAsync(string text) => ReplyAsync(text); | |||||
// Wrapping the message in quotes solves this. | // Wrapping the message in quotes solves this. | ||||
// This way, the system knows the entire message is to be parsed as a | // This way, the system knows the entire message is to be parsed as a | ||||
// single String. | // single String. | ||||
// e.g. | |||||
// e.g., | |||||
// !echo "Coffee Cake" | // !echo "Coffee Cake" |
@@ -7,8 +7,8 @@ title: Questions about Legacy Versions | |||||
## X, Y, Z does not work! It doesn't return a valid value anymore | ## X, Y, Z does not work! It doesn't return a valid value anymore | ||||
If you're currently using an older version in stable branch, please | |||||
upgrade to the latest pre-release version to ensure maximum | |||||
If you are currently using an older version of the stable branch, | |||||
please upgrade to the latest pre-release version to ensure maximum | |||||
compatibility. Several features may be broken in older | compatibility. Several features may be broken in older | ||||
versions and will likely not be fixed in the version branch due to | versions and will likely not be fixed in the version branch due to | ||||
their breaking nature. | their breaking nature. |
@@ -107,7 +107,7 @@ be found in @Guides.Commands.TypeReaders. | |||||
#### Optional Parameters | #### Optional Parameters | ||||
Parameters, by default, are always required. To make a parameter | Parameters, by default, are always required. To make a parameter | ||||
optional, give it a default value (i.e. `int num = 0`). | |||||
optional, give it a default value (i.e., `int num = 0`). | |||||
#### Parameters with Spaces | #### Parameters with Spaces | ||||
@@ -6,18 +6,18 @@ title: Post-command Execution Handling | |||||
# Preface | # Preface | ||||
When developing commands, you may want to consider building a | When developing commands, you may want to consider building a | ||||
post-execution handling system so you can have a finer control | |||||
post-execution handling system so you can have finer control | |||||
over commands. Discord.Net offers several post-execution workflows | over commands. Discord.Net offers several post-execution workflows | ||||
for you to work with. | for you to work with. | ||||
If you recall, in the [Command Guide], we've shown the following | |||||
If you recall, in the [Command Guide], we have shown the following | |||||
example for executing and handling commands, | example for executing and handling commands, | ||||
[!code[Command Handler](samples/command_handler.cs)] | [!code[Command Handler](samples/command_handler.cs)] | ||||
You may notice that after we perform [ExecuteAsync], we store the | You may notice that after we perform [ExecuteAsync], we store the | ||||
result and print it to the chat. This is essentially the most | |||||
basic post-execution handling. | |||||
result and print it to the chat, essentially creating the most | |||||
fundamental form of a post-execution handler. | |||||
With this in mind, we could start doing things like the following, | With this in mind, we could start doing things like the following, | ||||
@@ -25,8 +25,8 @@ With this in mind, we could start doing things like the following, | |||||
However, this may not always be preferred, because you are | However, this may not always be preferred, because you are | ||||
creating your post-execution logic *with* the essential command | creating your post-execution logic *with* the essential command | ||||
handler. This could lead to messy code and could potentially be a | |||||
violation of the SRP (Single Responsibility Principle). | |||||
handler. This design could lead to messy code and could potentially | |||||
be a violation of the SRP (Single Responsibility Principle). | |||||
Another major issue is if your command is marked with | Another major issue is if your command is marked with | ||||
`RunMode.Async`, [ExecuteAsync] will **always** return a successful | `RunMode.Async`, [ExecuteAsync] will **always** return a successful | ||||
@@ -37,8 +37,8 @@ about the impact in the [FAQ](xref:FAQ.Commands). | |||||
Enter [CommandExecuted], an event that was introduced in | Enter [CommandExecuted], an event that was introduced in | ||||
Discord.Net 2.0. This event is raised whenever a command is | Discord.Net 2.0. This event is raised whenever a command is | ||||
successfully executed **without any run-time exceptions** or **without | |||||
any parsing or precondition failure**. This means this event can be | |||||
successfully executed **without any run-time exceptions** or **any | |||||
parsing or precondition failure**. This means this event can be | |||||
used to streamline your post-execution design, and the best thing | used to streamline your post-execution design, and the best thing | ||||
about this event is that it is not prone to `RunMode.Async`'s | about this event is that it is not prone to `RunMode.Async`'s | ||||
[ExecuteAsync] drawbacks. | [ExecuteAsync] drawbacks. | ||||
@@ -52,7 +52,7 @@ next? We can take this further by using [RuntimeResult]. | |||||
### RuntimeResult | ### RuntimeResult | ||||
`RuntimeResult` was originally introduced in 1.0 to allow | |||||
`RuntimeResult` was initially introduced in 1.0 to allow | |||||
developers to centralize their command result logic. | developers to centralize their command result logic. | ||||
In other words, it is a result type that is designed to be | In other words, it is a result type that is designed to be | ||||
returned when the command has finished its execution. | returned when the command has finished its execution. | ||||
@@ -62,7 +62,7 @@ However, it wasn't widely adopted due to the aforementioned | |||||
result-handler via the [CommandExecuted] event, we can start | result-handler via the [CommandExecuted] event, we can start | ||||
making use of this class. | making use of this class. | ||||
The best way to make use of it is to create your own version of | |||||
The best way to make use of it is to create your version of | |||||
`RuntimeResult`. You can achieve this by inheriting the `RuntimeResult` | `RuntimeResult`. You can achieve this by inheriting the `RuntimeResult` | ||||
class. | class. | ||||
@@ -71,16 +71,16 @@ of `RuntimeResult`, | |||||
[!code[Base Use](samples/customresult_base.cs)] | [!code[Base Use](samples/customresult_base.cs)] | ||||
The sky's the limit from here. You can add any additional information | |||||
you'd like regarding the execution result. | |||||
The sky is the limit from here. You can add any additional information | |||||
you would like regarding the execution result. | |||||
For example, you may want to add your own result type or other | |||||
For example, you may want to add your result type or other | |||||
helpful information regarding the execution, or something | helpful information regarding the execution, or something | ||||
simple like static methods to help you create return types easily. | simple like static methods to help you create return types easily. | ||||
[!code[Extended Use](samples/customresult_extended.cs)] | [!code[Extended Use](samples/customresult_extended.cs)] | ||||
After you're done creating your own [RuntimeResult], you can | |||||
After you're done creating your [RuntimeResult], you can | |||||
implement it in your command by marking the command return type to | implement it in your command by marking the command return type to | ||||
`Task<RuntimeResult>`. | `Task<RuntimeResult>`. | ||||
@@ -100,12 +100,12 @@ And now we can check for it in our [CommandExecuted] handler: | |||||
## CommandService.Log Event | ## CommandService.Log Event | ||||
We have so far covered the handling of various result types, but we | We have so far covered the handling of various result types, but we | ||||
haven't talked about what to do if the command enters a catastrophic | |||||
failure (i.e. exceptions). To resolve this, we can make use of the | |||||
have not talked about what to do if the command enters a catastrophic | |||||
failure (i.e., exceptions). To resolve this, we can make use of the | |||||
[CommandService.Log] event. | [CommandService.Log] event. | ||||
All exceptions thrown during a command execution will be caught and | |||||
be sent to the Log event under the [LogMessage.Exception] property | |||||
All exceptions thrown during a command execution are caught and sent | |||||
to the Log event under the [LogMessage.Exception] property | |||||
as a [CommandException] type. The [CommandException] class allows | as a [CommandException] type. The [CommandException] class allows | ||||
us to access the exception thrown, as well as the context | us to access the exception thrown, as well as the context | ||||
of the command. | of the command. | ||||
@@ -11,14 +11,14 @@ stopped. | |||||
To start a connection, invoke the `StartAsync` method on a client that | To start a connection, invoke the `StartAsync` method on a client that | ||||
supports a WebSocket connection; to end a connection, invoke the | supports a WebSocket connection; to end a connection, invoke the | ||||
`StopAsync` method. This will gracefully close any open WebSocket or | |||||
`StopAsync` method, which gracefully closes any open WebSocket or | |||||
UdpSocket connections. | UdpSocket connections. | ||||
Since the Start/Stop methods only signal to an underlying connection | Since the Start/Stop methods only signal to an underlying connection | ||||
manager that a connection needs to be started, **they return before a | manager that a connection needs to be started, **they return before a | ||||
connection is actually made.** | |||||
connection is made.** | |||||
As a result, you will need to hook into one of the connection-state | |||||
As a result, you need to hook into one of the connection-state | |||||
based events to have an accurate representation of when a client is | based events to have an accurate representation of when a client is | ||||
ready for use. | ready for use. | ||||
@@ -29,7 +29,7 @@ ready to be used. | |||||
A separate event, `Ready`, is provided on [DiscordSocketClient], which | A separate event, `Ready`, is provided on [DiscordSocketClient], which | ||||
is raised only when the client has finished guild stream or guild | is raised only when the client has finished guild stream or guild | ||||
sync, and has a complete guild cache. | |||||
sync and has a completed guild cache. | |||||
[DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient | [DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient | ||||
@@ -41,8 +41,8 @@ sync, and has a complete guild cache. | |||||
> [!TIP] | > [!TIP] | ||||
> Avoid running long-running code on the gateway! If you deadlock the | > Avoid running long-running code on the gateway! If you deadlock the | ||||
> gateway (as explained in [events]), the connection manager will be | |||||
> unable to recover and reconnect. | |||||
> gateway (as explained in [events]), the connection manager will | |||||
> **NOT** be able to recover and reconnect. | |||||
Assuming the client disconnected because of a fault on Discord's end, | Assuming the client disconnected because of a fault on Discord's end, | ||||
and not a deadlock on your end, we will always attempt to reconnect | and not a deadlock on your end, we will always attempt to reconnect | ||||
@@ -50,6 +50,6 @@ and resume a connection. | |||||
Don't worry about trying to maintain your own connections, the | Don't worry about trying to maintain your own connections, the | ||||
connection manager is designed to be bulletproof and never fail - if | connection manager is designed to be bulletproof and never fail - if | ||||
your client doesn't manage to reconnect, you've found a bug! | |||||
your client does not manage to reconnect, you have found a bug! | |||||
[events]: xref:Guides.Concepts.Events | [events]: xref:Guides.Concepts.Events |
@@ -68,7 +68,7 @@ for use on another machine without installing the dependencies first. | |||||
This can be achieved by using the dotnet CLI too on the development | This can be achieved by using the dotnet CLI too on the development | ||||
machine: | machine: | ||||
`dotnet publish -c Release` | |||||
* `dotnet publish -c Release` | |||||
Additionally, you may want to target a specific platform when | Additionally, you may want to target a specific platform when | ||||
publishing the application so you may use the application without | publishing the application so you may use the application without | ||||
@@ -80,7 +80,7 @@ For example, when targeting a Windows 10 machine, you may want to use | |||||
the following to create the application in Windows executable | the following to create the application in Windows executable | ||||
format (.exe): | format (.exe): | ||||
`dotnet publish -c Release -r win10-x64` | |||||
* `dotnet publish -c Release -r win10-x64` | |||||
[.NET Core application deployment]: https://docs.microsoft.com/en-us/dotnet/core/deploying/ | [.NET Core application deployment]: https://docs.microsoft.com/en-us/dotnet/core/deploying/ | ||||
[Runtime ID]: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog | [Runtime ID]: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog |
@@ -56,7 +56,7 @@ DiscordSocketClient. | |||||
> [FAQ](xref:FAQ.Basics.GetStarted) page. | > [FAQ](xref:FAQ.Basics.GetStarted) page. | ||||
More detailed versions of entities can be pulled from the basic | More detailed versions of entities can be pulled from the basic | ||||
entities, e.g. `SocketGuild.GetUser`, which returns a | |||||
entities, e.g., `SocketGuild.GetUser`, which returns a | |||||
`SocketGuildUser`, or `SocketGuild.GetChannel`, which returns a | `SocketGuildUser`, or `SocketGuild.GetChannel`, which returns a | ||||
`SocketGuildChannel`. Again, you may need to cast these objects to get | `SocketGuildChannel`. Again, you may need to cast these objects to get | ||||
a variant of the type that you need. | a variant of the type that you need. | ||||
@@ -74,7 +74,7 @@ object. | |||||
[Cacheable]: xref:Discord.Cacheable`2 | [Cacheable]: xref:Discord.Cacheable`2 | ||||
> [!NOTE] | > [!NOTE] | ||||
> Many events relating to a Message entity (i.e. `MessageUpdated` and | |||||
> Many events relating to a Message entity (i.e., `MessageUpdated` and | |||||
> `ReactionAdded`) rely on the client's message cache, which is | > `ReactionAdded`) rely on the client's message cache, which is | ||||
> **not** enabled by default. Set the `MessageCacheSize` flag in | > **not** enabled by default. Set the `MessageCacheSize` flag in | ||||
> @Discord.WebSocket.DiscordSocketConfig to enable it. | > @Discord.WebSocket.DiscordSocketConfig to enable it. | ||||
@@ -16,7 +16,7 @@ section. | |||||
> [!WARNING] | > [!WARNING] | ||||
> Due to the nature of Discord.Net's event system, all log event | > Due to the nature of Discord.Net's event system, all log event | ||||
> handlers will be executed synchronously on the gateway thread. If your | > handlers will be executed synchronously on the gateway thread. If your | ||||
> log output will be dumped to a Web API (e.g. Sentry), you are advised | |||||
> log output will be dumped to a Web API (e.g., Sentry), you are advised | |||||
> to wrap your output in a `Task.Run` so the gateway thread does not | > to wrap your output in a `Task.Run` so the gateway thread does not | ||||
> become blocked while waiting for logging data to be written. | > become blocked while waiting for logging data to be written. | ||||
@@ -27,8 +27,8 @@ Discord Applications Portal first. | |||||
 |  | ||||
6. Confirm the popup. | 6. Confirm the popup. | ||||
7. If this bot will be public, check "Public Bot." **Do not tick any | |||||
other options!** | |||||
7. (Optional) If this bot will be public, check "Public Bot." | |||||
* **Do not tick any other options!** | |||||
[Discord Applications Portal]: https://discordapp.com/developers/applications/me | [Discord Applications Portal]: https://discordapp.com/developers/applications/me | ||||
@@ -38,15 +38,18 @@ Bots **cannot** use invite links; they must be explicitly invited | |||||
through the OAuth2 flow. | through the OAuth2 flow. | ||||
1. Open your bot's application on the [Discord Applications Portal]. | 1. Open your bot's application on the [Discord Applications Portal]. | ||||
2. Retrieve the application's **Client ID**. | |||||
2. Navigate to `OAuth2 URL Generator` and click on `Generate OAuth2 URL`. | |||||
 | |||||
 | |||||
3. Create an OAuth2 authorization URL | |||||
3. Select the permissions that you wish to assign your bot with. | |||||
- `https://discordapp.com/oauth2/authorize?client_id=<CLIENT ID>&scope=bot` | |||||
> [!NOTE] | |||||
> This will assign the bot with a special "managed" role that no | |||||
> one else can use. The permissions can be changed later in the | |||||
> roles settings if you ever change your mind! | |||||
4. Open the authorization URL in your browser. | |||||
4. Open the generated authorization URL in your browser. | |||||
5. Select a server. | 5. Select a server. | ||||
6. Click on authorize. | 6. Click on authorize. | ||||
@@ -40,7 +40,7 @@ Release builds of Discord.Net will be published to the | |||||
Development builds of Discord.Net, as well as add-ons, will be | Development builds of Discord.Net, as well as add-ons, will be | ||||
published to our [MyGet feed]. | published to our [MyGet feed]. | ||||
Direct feed link: `https://www.myget.org/F/discord-net/api/v3/index.json` | |||||
* Direct feed link: `https://www.myget.org/F/discord-net/api/v3/index.json` | |||||
Not sure how to add a direct feed? See how [with Visual Studio] or | Not sure how to add a direct feed? See how [with Visual Studio] or | ||||
[without Visual Studio]. | [without Visual Studio]. | ||||
@@ -28,13 +28,13 @@ addon will run on all platforms. | |||||
`Discord.Net.Rest` provides a set of concrete classes to be used | `Discord.Net.Rest` provides a set of concrete classes to be used | ||||
**strictly** with the REST portion of Discord's API. Entities in this | **strictly** with the REST portion of Discord's API. Entities in this | ||||
implementation are prefixed with `Rest` (e.g. `RestChannel`). | |||||
implementation are prefixed with `Rest` (e.g., `RestChannel`). | |||||
`Discord.Net.Rpc` provides a set of concrete classes that are used | `Discord.Net.Rpc` provides a set of concrete classes that are used | ||||
with Discord's RPC API. Entities in this implementation are prefixed | with Discord's RPC API. Entities in this implementation are prefixed | ||||
with `Rpc` (e.g. `RpcChannel`). | |||||
with `Rpc` (e.g., `RpcChannel`). | |||||
`Discord.Net.WebSocket` provides a set of concrete classes that are | `Discord.Net.WebSocket` provides a set of concrete classes that are | ||||
used primarily with Discord's WebSocket API or entities that are kept | used primarily with Discord's WebSocket API or entities that are kept | ||||
in cache. When developing bots, you will be using this implementation. | in cache. When developing bots, you will be using this implementation. | ||||
All entities are prefixed with `Socket` (e.g. `SocketChannel`). | |||||
All entities are prefixed with `Socket` (e.g., `SocketChannel`). |
@@ -17,7 +17,7 @@ understand these topics to some extent before proceeding. | |||||
Here are some examples: | Here are some examples: | ||||
1. [Official quick start guide] | |||||
1. [Official samples] | |||||
2. [Official template] | 2. [Official template] | ||||
> [!NOTE] | > [!NOTE] | ||||
@@ -26,7 +26,7 @@ Here are some examples: | |||||
> It is not meant to be something that will work out of the box. | > It is not meant to be something that will work out of the box. | ||||
[Official template]: https://github.com/foxbot/DiscordBotBase/tree/csharp/src/DiscordBot | [Official template]: https://github.com/foxbot/DiscordBotBase/tree/csharp/src/DiscordBot | ||||
[Official quick start guide]: https://github.com/RogueException/Discord.Net/blob/dev/docs/guides/getting_started/samples/first-bot/structure.cs | |||||
[Official samples]: https://github.com/RogueException/Discord.Net/tree/dev/samples | |||||
[Task-based Asynchronous Pattern]: https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap | [Task-based Asynchronous Pattern]: https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap | ||||
[polymorphism]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/polymorphism | [polymorphism]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/polymorphism | ||||
[interface]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ | [interface]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ | ||||
@@ -6,6 +6,7 @@ namespace Discord.Commands | |||||
/// <summary> | /// <summary> | ||||
/// Requires the parameter to pass the specified precondition before execution can begin. | /// Requires the parameter to pass the specified precondition before execution can begin. | ||||
/// </summary> | /// </summary> | ||||
/// <seealso cref="PreconditionAttribute"/> | |||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] | [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] | ||||
public abstract class ParameterPreconditionAttribute : Attribute | public abstract class ParameterPreconditionAttribute : Attribute | ||||
{ | { | ||||
@@ -3,20 +3,29 @@ using System.Threading.Tasks; | |||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
/// <summary> Requires the module or class to pass the specified precondition before execution can begin. </summary> | |||||
/// <summary> | |||||
/// Requires the module or class to pass the specified precondition before execution can begin. | |||||
/// </summary> | |||||
/// <seealso cref="ParameterPreconditionAttribute"/> | |||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = true)] | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = true)] | ||||
public abstract class PreconditionAttribute : Attribute | public abstract class PreconditionAttribute : Attribute | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Specify a group that this precondition belongs to. | |||||
/// Specifies a group that this precondition belongs to. | |||||
/// </summary> | /// </summary> | ||||
/// <remarks> | /// <remarks> | ||||
/// <see cref="Preconditions" /> of the same group require only one of the preconditions to pass in order to | /// <see cref="Preconditions" /> of the same group require only one of the preconditions to pass in order to | ||||
/// be successful (A || B). Specifying <see cref="Group" /> = <see langword="null" /> or not at all will | |||||
/// be successful (A || B). Specifying <see cref="Group" /> = <c>null</c> or not at all will | |||||
/// require *all* preconditions to pass, just like normal (A && B). | /// require *all* preconditions to pass, just like normal (A && B). | ||||
/// </remarks> | /// </remarks> | ||||
public string Group { get; set; } = null; | public string Group { get; set; } = null; | ||||
/// <summary> | |||||
/// Checks if the <paramref name="command"/> has the sufficient permission to be executed. | |||||
/// </summary> | |||||
/// <param name="context">The context of the command.</param> | |||||
/// <param name="command">The command being executed.</param> | |||||
/// <param name="services">The service collection used for dependency injection.</param> | |||||
public abstract Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services); | public abstract Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services); | ||||
} | } | ||||
} | } |
@@ -54,9 +54,9 @@ namespace Discord.Commands | |||||
if (GuildPermission.HasValue) | if (GuildPermission.HasValue) | ||||
{ | { | ||||
if (guildUser == null) | if (guildUser == null) | ||||
return Task.FromResult(PreconditionResult.FromError("Command must be used in a guild channel")); | |||||
return Task.FromResult(PreconditionResult.FromError("Command must be used in a guild channel.")); | |||||
if (!guildUser.GuildPermissions.Has(GuildPermission.Value)) | if (!guildUser.GuildPermissions.Has(GuildPermission.Value)) | ||||
return Task.FromResult(PreconditionResult.FromError($"User requires guild permission {GuildPermission.Value}")); | |||||
return Task.FromResult(PreconditionResult.FromError($"User requires guild permission {GuildPermission.Value}.")); | |||||
} | } | ||||
if (ChannelPermission.HasValue) | if (ChannelPermission.HasValue) | ||||
@@ -68,7 +68,7 @@ namespace Discord.Commands | |||||
perms = ChannelPermissions.All(context.Channel); | perms = ChannelPermissions.All(context.Channel); | ||||
if (!perms.Has(ChannelPermission.Value)) | if (!perms.Has(ChannelPermission.Value)) | ||||
return Task.FromResult(PreconditionResult.FromError($"User requires channel permission {ChannelPermission.Value}")); | |||||
return Task.FromResult(PreconditionResult.FromError($"User requires channel permission {ChannelPermission.Value}.")); | |||||
} | } | ||||
return Task.FromResult(PreconditionResult.FromSuccess()); | return Task.FromResult(PreconditionResult.FromSuccess()); | ||||
@@ -129,7 +129,7 @@ namespace Discord.Commands | |||||
/// <typeparam name="T">The type of module.</typeparam> | /// <typeparam name="T">The type of module.</typeparam> | ||||
/// <param name="services"> | /// <param name="services"> | ||||
/// The <see cref="IServiceProvider" /> for your dependency injection solution, if using one - otherwise, pass | /// The <see cref="IServiceProvider" /> for your dependency injection solution, if using one - otherwise, pass | ||||
/// <see langword="null" />. | |||||
/// <c>null</c>. | |||||
/// </param> | /// </param> | ||||
/// <returns> | /// <returns> | ||||
/// A built module. | /// A built module. | ||||
@@ -144,7 +144,7 @@ namespace Discord.Commands | |||||
/// <param name="type">The type of module.</param> | /// <param name="type">The type of module.</param> | ||||
/// <param name="services"> | /// <param name="services"> | ||||
/// The <see cref="IServiceProvider" /> for your dependency injection solution, if using one - otherwise, pass | /// The <see cref="IServiceProvider" /> for your dependency injection solution, if using one - otherwise, pass | ||||
/// <see langword="null" />. | |||||
/// <c>null</c>. | |||||
/// </param> | /// </param> | ||||
/// <returns> | /// <returns> | ||||
/// A built module. | /// A built module. | ||||
@@ -183,7 +183,7 @@ namespace Discord.Commands | |||||
/// <param name="assembly">The <see cref="Assembly" /> containing command modules.</param> | /// <param name="assembly">The <see cref="Assembly" /> containing command modules.</param> | ||||
/// <param name="services"> | /// <param name="services"> | ||||
/// An <see cref="IServiceProvider" /> for your dependency injection solution, if using one - otherwise, pass | /// An <see cref="IServiceProvider" /> for your dependency injection solution, if using one - otherwise, pass | ||||
/// <see langword="null" />. | |||||
/// <c>null</c>. | |||||
/// </param> | /// </param> | ||||
/// <returns> | /// <returns> | ||||
/// A collection of built modules. | /// A collection of built modules. | ||||
@@ -6,19 +6,23 @@ using System.Threading.Tasks; | |||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
/// <summary> | |||||
/// A <see cref="TypeReader"/> for parsing objects implementing <see cref="IChannel"/>. | |||||
/// </summary> | |||||
/// <typeparam name="T">The type to be checked; must implement <see cref="IChannel"/>.</typeparam> | |||||
public class ChannelTypeReader<T> : TypeReader | public class ChannelTypeReader<T> : TypeReader | ||||
where T : class, IChannel | where T : class, IChannel | ||||
{ | { | ||||
/// <inheritdoc /> | |||||
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services) | public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services) | ||||
{ | { | ||||
if (context.Guild != null) | if (context.Guild != null) | ||||
{ | { | ||||
var results = new Dictionary<ulong, TypeReaderValue>(); | var results = new Dictionary<ulong, TypeReaderValue>(); | ||||
var channels = await context.Guild.GetChannelsAsync(CacheMode.CacheOnly).ConfigureAwait(false); | var channels = await context.Guild.GetChannelsAsync(CacheMode.CacheOnly).ConfigureAwait(false); | ||||
ulong id; | |||||
//By Mention (1.0) | //By Mention (1.0) | ||||
if (MentionUtils.TryParseChannel(input, out id)) | |||||
if (MentionUtils.TryParseChannel(input, out ulong id)) | |||||
AddResult(results, await context.Guild.GetChannelAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T, 1.00f); | AddResult(results, await context.Guild.GetChannelAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) as T, 1.00f); | ||||
//By Id (0.9) | //By Id (0.9) | ||||
@@ -4,15 +4,18 @@ using System.Threading.Tasks; | |||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
/// <summary> | |||||
/// A <see cref="TypeReader"/> for parsing objects implementing <see cref="IMessage"/>. | |||||
/// </summary> | |||||
/// <typeparam name="T">The type to be checked; must implement <see cref="IMessage"/>.</typeparam> | |||||
public class MessageTypeReader<T> : TypeReader | public class MessageTypeReader<T> : TypeReader | ||||
where T : class, IMessage | where T : class, IMessage | ||||
{ | { | ||||
/// <inheritdoc /> | |||||
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services) | public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services) | ||||
{ | { | ||||
ulong id; | |||||
//By Id (1.0) | //By Id (1.0) | ||||
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id)) | |||||
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out ulong id)) | |||||
{ | { | ||||
if (await context.Channel.GetMessageAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) is T msg) | if (await context.Channel.GetMessageAsync(id, CacheMode.CacheOnly).ConfigureAwait(false) is T msg) | ||||
return TypeReaderResult.FromSuccess(msg); | return TypeReaderResult.FromSuccess(msg); | ||||
@@ -6,9 +6,14 @@ using System.Threading.Tasks; | |||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
/// <summary> | |||||
/// A <see cref="TypeReader"/> for parsing objects implementing <see cref="IRole"/>. | |||||
/// </summary> | |||||
/// <typeparam name="T">The type to be checked; must implement <see cref="IRole"/>.</typeparam> | |||||
public class RoleTypeReader<T> : TypeReader | public class RoleTypeReader<T> : TypeReader | ||||
where T : class, IRole | where T : class, IRole | ||||
{ | { | ||||
/// <inheritdoc /> | |||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services) | public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services) | ||||
{ | { | ||||
if (context.Guild != null) | if (context.Guild != null) | ||||
@@ -1,10 +1,22 @@ | |||||
using System; | |||||
using System; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
/// <summary> | |||||
/// Defines a reader class that parses user input into a specified type. | |||||
/// </summary> | |||||
public abstract class TypeReader | public abstract class TypeReader | ||||
{ | { | ||||
/// <summary> | |||||
/// Attempts to parse the <paramref name="input"/> into the desired type. | |||||
/// </summary> | |||||
/// <param name="context">The context of the command.</param> | |||||
/// <param name="input">The raw input of the command.</param> | |||||
/// <param name="services">The service collection used for dependency injection.</param> | |||||
/// <returns> | |||||
/// An awaitable Task containing the result of the type reading process. | |||||
/// </returns> | |||||
public abstract Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services); | public abstract Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services); | ||||
} | } | ||||
} | } |
@@ -7,9 +7,14 @@ using System.Threading.Tasks; | |||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
/// <summary> | |||||
/// A <see cref="TypeReader"/> for parsing objects implementing <see cref="IUser"/>. | |||||
/// </summary> | |||||
/// <typeparam name="T">The type to be checked; must implement <see cref="IUser"/>.</typeparam> | |||||
public class UserTypeReader<T> : TypeReader | public class UserTypeReader<T> : TypeReader | ||||
where T : class, IUser | where T : class, IUser | ||||
{ | { | ||||
/// <inheritdoc /> | |||||
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services) | public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services) | ||||
{ | { | ||||
var results = new Dictionary<ulong, TypeReaderValue>(); | var results = new Dictionary<ulong, TypeReaderValue>(); | ||||
@@ -72,8 +77,8 @@ namespace Discord.Commands | |||||
.ForEachAsync(channelUser => AddResult(results, channelUser as T, (channelUser as IGuildUser).Nickname == input ? 0.65f : 0.55f)) | .ForEachAsync(channelUser => AddResult(results, channelUser as T, (channelUser as IGuildUser).Nickname == input ? 0.65f : 0.55f)) | ||||
.ConfigureAwait(false); | .ConfigureAwait(false); | ||||
foreach (var guildUser in guildUsers.Where(x => string.Equals(input, (x as IGuildUser).Nickname, StringComparison.OrdinalIgnoreCase))) | |||||
AddResult(results, guildUser as T, (guildUser as IGuildUser).Nickname == input ? 0.60f : 0.50f); | |||||
foreach (var guildUser in guildUsers.Where(x => string.Equals(input, x.Nickname, StringComparison.OrdinalIgnoreCase))) | |||||
AddResult(results, guildUser as T, guildUser.Nickname == input ? 0.60f : 0.50f); | |||||
} | } | ||||
if (results.Count > 0) | if (results.Count > 0) | ||||
@@ -8,7 +8,7 @@ namespace Discord.Commands | |||||
/// <summary> | /// <summary> | ||||
/// Initializes a new <see cref="RuntimeResult" /> class with the type of error and reason. | /// Initializes a new <see cref="RuntimeResult" /> class with the type of error and reason. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="error">The type of failure, or <see langword="null" /> if none.</param> | |||||
/// <param name="error">The type of failure, or <c>null</c> if none.</param> | |||||
/// <param name="reason">The reason of failure.</param> | /// <param name="reason">The reason of failure.</param> | ||||
protected RuntimeResult(CommandError? error, string reason) | protected RuntimeResult(CommandError? error, string reason) | ||||
{ | { | ||||
@@ -8,13 +8,26 @@ namespace Discord | |||||
public static class CDN | public static class CDN | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Returns the Discord developer application icon. | |||||
/// Returns an application icon URL. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="appId">The application identifier.</param> | |||||
/// <param name="iconId">The icon identifier.</param> | |||||
/// <returns> | |||||
/// A URL pointing to the application's icon. | |||||
/// </returns> | |||||
public static string GetApplicationIconUrl(ulong appId, string iconId) | public static string GetApplicationIconUrl(ulong appId, string iconId) | ||||
=> iconId != null ? $"{DiscordConfig.CDNUrl}app-icons/{appId}/{iconId}.jpg" : null; | => iconId != null ? $"{DiscordConfig.CDNUrl}app-icons/{appId}/{iconId}.jpg" : null; | ||||
/// <summary> | /// <summary> | ||||
/// Returns the user avatar URL based on the <paramref name="size"/> and <see cref="ImageFormat" />. | |||||
/// Returns a user avatar URL. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="userId">The user snowflake identifier.</param> | |||||
/// <param name="avatarId">The avatar identifier.</param> | |||||
/// <param name="size">The size of the image to return in. This can be any power of two between 16 and 2048.</param> | |||||
/// <param name="format">The format to return.</param> | |||||
/// <returns> | |||||
/// A URL pointing to the user's avatar in the specified size. | |||||
/// </returns> | |||||
public static string GetUserAvatarUrl(ulong userId, string avatarId, ushort size, ImageFormat format) | public static string GetUserAvatarUrl(ulong userId, string avatarId, ushort size, ImageFormat format) | ||||
{ | { | ||||
if (avatarId == null) | if (avatarId == null) | ||||
@@ -26,34 +39,64 @@ namespace Discord | |||||
/// Returns the default user avatar URL. | /// Returns the default user avatar URL. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="discriminator">The discriminator value of a user.</param> | /// <param name="discriminator">The discriminator value of a user.</param> | ||||
/// <returns> | |||||
/// A URL pointing to the user's default avatar when one isn't set. | |||||
/// </returns> | |||||
public static string GetDefaultUserAvatarUrl(ushort discriminator) | public static string GetDefaultUserAvatarUrl(ushort discriminator) | ||||
{ | { | ||||
return $"{DiscordConfig.CDNUrl}embed/avatars/{discriminator % 5}.png"; | return $"{DiscordConfig.CDNUrl}embed/avatars/{discriminator % 5}.png"; | ||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// Returns the icon URL associated with the given guild ID. | |||||
/// Returns an icon URL. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="guildId">The guild snowflake identifier.</param> | |||||
/// <param name="iconId">The icon identifier.</param> | |||||
/// <returns> | |||||
/// A URL pointing to the guild's icon. | |||||
/// </returns> | |||||
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 the guild splash URL associated with the given guild and splash ID. | |||||
/// Returns a guild splash URL. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="guildId">The guild snowflake identifier.</param> | |||||
/// <param name="splashId">The splash icon identifier.</param> | |||||
/// <returns> | |||||
/// A URL pointing to the guild's icon. | |||||
/// </returns> | |||||
public static string GetGuildSplashUrl(ulong guildId, string splashId) | public static string GetGuildSplashUrl(ulong guildId, string splashId) | ||||
=> splashId != null ? $"{DiscordConfig.CDNUrl}splashes/{guildId}/{splashId}.jpg" : null; | => splashId != null ? $"{DiscordConfig.CDNUrl}splashes/{guildId}/{splashId}.jpg" : null; | ||||
/// <summary> | /// <summary> | ||||
/// Returns the channel icon URL associated with the given guild and icon ID. | |||||
/// Returns a channel icon URL. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="channelId">The channel snowflake identifier.</param> | |||||
/// <param name="iconId">The icon identifier.</param> | |||||
/// <returns> | |||||
/// A URL pointing to the channel's icon. | |||||
/// </returns> | |||||
public static string GetChannelIconUrl(ulong channelId, string iconId) | public static string GetChannelIconUrl(ulong channelId, string iconId) | ||||
=> iconId != null ? $"{DiscordConfig.CDNUrl}channel-icons/{channelId}/{iconId}.jpg" : null; | => iconId != null ? $"{DiscordConfig.CDNUrl}channel-icons/{channelId}/{iconId}.jpg" : null; | ||||
/// <summary> | /// <summary> | ||||
/// Returns the emoji URL based on the emoji ID. | |||||
/// Returns an emoji URL. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="emojiId">The emoji snowflake identifier.</param> | |||||
/// <param name="animated">Whether this emoji is animated.</param> | |||||
/// <returns> | |||||
/// A URL pointing to the custom emote. | |||||
/// </returns> | |||||
public static string GetEmojiUrl(ulong emojiId, bool animated) | public static string GetEmojiUrl(ulong emojiId, bool animated) | ||||
=> $"{DiscordConfig.CDNUrl}emojis/{emojiId}.{(animated ? "gif" : "png")}"; | => $"{DiscordConfig.CDNUrl}emojis/{emojiId}.{(animated ? "gif" : "png")}"; | ||||
/// <summary> | /// <summary> | ||||
/// Returns the rich presence asset URL based on the asset ID and <see cref="ImageFormat" />. | |||||
/// Returns a Rich Presence asset URL. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="appId">The application identifier.</param> | |||||
/// <param name="assetId">The asset identifier.</param> | |||||
/// <param name="size">The size of the image to return in. This can be any power of two between 16 and 2048.</param> | |||||
/// <param name="format">The format to return.</param> | |||||
/// <returns> | |||||
/// A URL pointing to the asset image in the specified size. | |||||
/// </returns> | |||||
public static string GetRichAssetUrl(ulong appId, string assetId, ushort size, ImageFormat format) | public static string GetRichAssetUrl(ulong appId, string assetId, ushort size, ImageFormat format) | ||||
{ | { | ||||
string extension = FormatToExtension(format, ""); | string extension = FormatToExtension(format, ""); | ||||
@@ -61,10 +104,21 @@ namespace Discord | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// Returns the Spotify album URL based on the album art ID. | |||||
/// Returns a Spotify album URL. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="albumArtId">The identifier for the album art (e.g. 6be8f4c8614ecf4f1dd3ebba8d8692d8ce4951ac).</param> | |||||
/// <returns> | |||||
/// A URL pointing to the Spotify album art. | |||||
/// </returns> | |||||
public static string GetSpotifyAlbumArtUrl(string albumArtId) | public static string GetSpotifyAlbumArtUrl(string albumArtId) | ||||
=> $"https://i.scdn.co/image/{albumArtId}"; | => $"https://i.scdn.co/image/{albumArtId}"; | ||||
/// <summary> | |||||
/// Returns a Spotify direct URL for a track. | |||||
/// </summary> | |||||
/// <param name="trackId">The identifier for the track (e.g. 4uLU6hMCjMI75M1A2tKUQC).</param> | |||||
/// <returns> | |||||
/// A URL pointing to the Spotify track. | |||||
/// </returns> | |||||
public static string GetSpotifyDirectUrl(string trackId) | public static string GetSpotifyDirectUrl(string trackId) | ||||
=> $"https://open.spotify.com/track/{trackId}"; | => $"https://open.spotify.com/track/{trackId}"; | ||||
@@ -8,68 +8,116 @@ namespace Discord | |||||
public class DiscordConfig | public class DiscordConfig | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Returns the gateway version Discord.Net uses. | |||||
/// Returns the API version Discord.Net uses. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A 32-bit integer representing the API version that Discord.Net uses to communicate with Discord. | |||||
/// <para>A list of available API version can be seen on the official | |||||
/// <see href="https://discordapp.com/developers/docs/reference#api-versioning">Discord API documentation</see> | |||||
/// .</para> | |||||
/// </returns> | |||||
public const int APIVersion = 6; | public const int APIVersion = 6; | ||||
/// <summary> | /// <summary> | ||||
/// Gets the Discord.Net version, including the build number. | /// Gets the Discord.Net version, including the build number. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A string containing the detailed version information, including its build number; <c>Unknown</c> when | |||||
/// the version fails to be fetched. | |||||
/// </returns> | |||||
public static string Version { get; } = | public static string Version { get; } = | ||||
typeof(DiscordConfig).GetTypeInfo().Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? | typeof(DiscordConfig).GetTypeInfo().Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? | ||||
typeof(DiscordConfig).GetTypeInfo().Assembly.GetName().Version.ToString(3) ?? | |||||
typeof(DiscordConfig).GetTypeInfo().Assembly.GetName().Version.ToString(3) ?? | |||||
"Unknown"; | "Unknown"; | ||||
/// <summary> | /// <summary> | ||||
/// Gets the user agent that Discord.Net uses in its clients. | /// Gets the user agent that Discord.Net uses in its clients. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The user agent used in each Discord.Net request. | |||||
/// </returns> | |||||
public static string UserAgent { get; } = $"DiscordBot (https://github.com/RogueException/Discord.Net, v{Version})"; | public static string UserAgent { get; } = $"DiscordBot (https://github.com/RogueException/Discord.Net, v{Version})"; | ||||
/// <summary> | /// <summary> | ||||
/// Returns the base Discord API URL. | /// Returns the base Discord API URL. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The Discord API URL using <see cref="APIVersion"/>. | |||||
/// </returns> | |||||
public static readonly string APIUrl = $"https://discordapp.com/api/v{APIVersion}/"; | public static readonly string APIUrl = $"https://discordapp.com/api/v{APIVersion}/"; | ||||
/// <summary> | /// <summary> | ||||
/// Returns the base Discord CDN URL. | /// Returns the base Discord CDN URL. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The base Discord Content Delivery Network (CDN) URL. | |||||
/// </returns> | |||||
public const string CDNUrl = "https://cdn.discordapp.com/"; | public const string CDNUrl = "https://cdn.discordapp.com/"; | ||||
/// <summary> | /// <summary> | ||||
/// Returns the base Discord invite URL. | |||||
/// Returns the base Discord invite URL. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The base Discord invite URL. | |||||
/// </returns> | |||||
public const string InviteUrl = "https://discord.gg/"; | public const string InviteUrl = "https://discord.gg/"; | ||||
/// <summary> | /// <summary> | ||||
/// Returns the default timeout for requests. | /// Returns the default timeout for requests. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The amount of time it takes in milliseconds before a request is timed out. | |||||
/// </returns> | |||||
public const int DefaultRequestTimeout = 15000; | public const int DefaultRequestTimeout = 15000; | ||||
/// <summary> | /// <summary> | ||||
/// Returns the max length for a Discord message. | /// Returns the max length for a Discord message. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The maximum length of a message allowed by Discord. | |||||
/// </returns> | |||||
public const int MaxMessageSize = 2000; | public const int MaxMessageSize = 2000; | ||||
/// <summary> | /// <summary> | ||||
/// Returns the max messages allowed to be in a request. | /// Returns the max messages allowed to be in a request. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The maximum number of messages that can be gotten per-batch. | |||||
/// </returns> | |||||
public const int MaxMessagesPerBatch = 100; | public const int MaxMessagesPerBatch = 100; | ||||
/// <summary> | /// <summary> | ||||
/// Returns the max users allowed to be in a request. | /// Returns the max users allowed to be in a request. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The maximum number of users that can be gotten per-batch. | |||||
/// </returns> | |||||
public const int MaxUsersPerBatch = 1000; | public const int MaxUsersPerBatch = 1000; | ||||
/// <summary> | /// <summary> | ||||
/// Returns the max guilds allowed to be in a request. | /// Returns the max guilds allowed to be in a request. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The maximum number of guilds that can be gotten per-batch. | |||||
/// </returns> | |||||
public const int MaxGuildsPerBatch = 100; | public const int MaxGuildsPerBatch = 100; | ||||
public const int MaxAuditLogEntriesPerBatch = 100; | |||||
/// <summary> | /// <summary> | ||||
/// Gets or sets how a request should act in the case of an error, by default. | /// Gets or sets how a request should act in the case of an error, by default. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The currently set <see cref="RetryMode"/>. | |||||
/// </returns> | |||||
public RetryMode DefaultRetryMode { get; set; } = RetryMode.AlwaysRetry; | public RetryMode DefaultRetryMode { get; set; } = RetryMode.AlwaysRetry; | ||||
/// <summary> | /// <summary> | ||||
/// Gets or sets the minimum log level severity that will be sent to the Log event. | /// Gets or sets the minimum log level severity that will be sent to the Log event. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The currently set <see cref="LogSeverity"/> for logging level. | |||||
/// </returns> | |||||
public LogSeverity LogLevel { get; set; } = LogSeverity.Info; | public LogSeverity LogLevel { get; set; } = LogSeverity.Info; | ||||
/// <summary> | /// <summary> | ||||
/// Gets or sets whether the initial log entry should be printed. | /// Gets or sets whether the initial log entry should be printed. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks> | |||||
/// If set to <c>true</c>, the library will attempt to print the current version of the library, as well as | |||||
/// the API version it uses on startup. | |||||
/// </remarks> | |||||
internal bool DisplayInitialLog { get; set; } = true; | internal bool DisplayInitialLog { get; set; } = true; | ||||
} | } | ||||
} | } |
@@ -19,7 +19,7 @@ namespace Discord | |||||
public string ImageId { get; internal set; } | public string ImageId { get; internal set; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns the image URL of the asset, or <see langword="null"/> when the application ID does not exist. | |||||
/// Returns the image URL of the asset, or <c>null</c> when the application ID does not exist. | |||||
/// </summary> | /// </summary> | ||||
public string GetImageUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) | public string GetImageUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) | ||||
=> ApplicationId.HasValue ? CDN.GetRichAssetUrl(ApplicationId.Value, ImageId, size, format) : null; | => ApplicationId.HasValue ? CDN.GetRichAssetUrl(ApplicationId.Value, ImageId, size, format) : null; | ||||
@@ -13,36 +13,65 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Gets the song's artist(s). | /// Gets the song's artist(s). | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A collection of string containing all artists featured in the track (e.g. <c>Avicii</c>; <c>Rita Ora</c>). | |||||
/// </returns> | |||||
public IReadOnlyCollection<string> Artists { get; internal set; } | public IReadOnlyCollection<string> Artists { get; internal set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the Spotify album title of the song. | /// Gets the Spotify album title of the song. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A string containing the name of the album (e.g. <c>AVĪCI (01)</c>). | |||||
/// </returns> | |||||
public string AlbumTitle { get; internal set; } | public string AlbumTitle { get; internal set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the track title of the song. | /// Gets the track title of the song. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A string containing the name of the song (e.g. <c>Lonely Together (feat. Rita Ora)</c>). | |||||
/// </returns> | |||||
public string TrackTitle { get; internal set; } | public string TrackTitle { get; internal set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the duration of the song. | /// Gets the duration of the song. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A <see cref="TimeSpan"/> containing the duration of the song. | |||||
/// </returns> | |||||
public TimeSpan? Duration { get; internal set; } | public TimeSpan? Duration { get; internal set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the track ID of the song. | /// Gets the track ID of the song. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A string containing the Spotify ID of the track (e.g. <c>7DoN0sCGIT9IcLrtBDm4f0</c>). | |||||
/// </returns> | |||||
public string TrackId { get; internal set; } | public string TrackId { get; internal set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the session ID of the song. | /// Gets the session ID of the song. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks> | |||||
/// The purpose of this property is currently unknown. | |||||
/// </remarks> | |||||
/// <returns> | |||||
/// A string containing the session ID. | |||||
/// </returns> | |||||
public string SessionId { get; internal set; } | public string SessionId { get; internal set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the URL of the album art. | /// Gets the URL of the album art. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A URL pointing to the album art of the track (e.g. | |||||
/// <c>https://i.scdn.co/image/ba2fd8823d42802c2f8738db0b33a4597f2f39e7</c>). | |||||
/// </returns> | |||||
public string AlbumArtUrl { get; internal set; } | public string AlbumArtUrl { get; internal set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the direct Spotify URL of the track. | /// Gets the direct Spotify URL of the track. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A URL pointing directly to the track on Spotify. (e.g. | |||||
/// <c>https://open.spotify.com/track/7DoN0sCGIT9IcLrtBDm4f0</c>). | |||||
/// </returns> | |||||
public string TrackUrl { get; internal set; } | public string TrackUrl { get; internal set; } | ||||
internal SpotifyGame() { } | internal SpotifyGame() { } | ||||
@@ -50,6 +79,10 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Gets the full information of the song. | /// Gets the full information of the song. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A string containing the full information of the song (e.g. | |||||
/// <c>Avicii, Rita Ora - Lonely Together (feat. Rita Ora) (3:08)</c> | |||||
/// </returns> | |||||
public override string ToString() => $"{string.Join(", ", Artists)} - {TrackTitle} ({Duration})"; | public override string ToString() => $"{string.Join(", ", Artists)} - {TrackTitle} ({Duration})"; | ||||
private string DebuggerDisplay => $"{Name} (Spotify)"; | private string DebuggerDisplay => $"{Name} (Spotify)"; | ||||
} | } | ||||
@@ -0,0 +1,50 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// The action type within a <see cref="IAuditLogEntry"/> | |||||
/// </summary> | |||||
public enum ActionType | |||||
{ | |||||
GuildUpdated = 1, | |||||
ChannelCreated = 10, | |||||
ChannelUpdated = 11, | |||||
ChannelDeleted = 12, | |||||
OverwriteCreated = 13, | |||||
OverwriteUpdated = 14, | |||||
OverwriteDeleted = 15, | |||||
Kick = 20, | |||||
Prune = 21, | |||||
Ban = 22, | |||||
Unban = 23, | |||||
MemberUpdated = 24, | |||||
MemberRoleUpdated = 25, | |||||
RoleCreated = 30, | |||||
RoleUpdated = 31, | |||||
RoleDeleted = 32, | |||||
InviteCreated = 40, | |||||
InviteUpdated = 41, | |||||
InviteDeleted = 42, | |||||
WebhookCreated = 50, | |||||
WebhookUpdated = 51, | |||||
WebhookDeleted = 52, | |||||
EmojiCreated = 60, | |||||
EmojiUpdated = 61, | |||||
EmojiDeleted = 62, | |||||
MessageDeleted = 72 | |||||
} | |||||
} |
@@ -0,0 +1,14 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Represents data applied to an <see cref="IAuditLogEntry"/> | |||||
/// </summary> | |||||
public interface IAuditLogData | |||||
{ } | |||||
} |
@@ -0,0 +1,34 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Represents an entry in an audit log | |||||
/// </summary> | |||||
public interface IAuditLogEntry : IEntity<ulong> | |||||
{ | |||||
/// <summary> | |||||
/// The action which occured to create this entry | |||||
/// </summary> | |||||
ActionType Action { get; } | |||||
/// <summary> | |||||
/// The data for this entry. May be <see cref="null"/> if no data was available. | |||||
/// </summary> | |||||
IAuditLogData Data { get; } | |||||
/// <summary> | |||||
/// The user responsible for causing the changes | |||||
/// </summary> | |||||
IUser User { get; } | |||||
/// <summary> | |||||
/// The reason behind the change. May be <see cref="null"/> if no reason was provided. | |||||
/// </summary> | |||||
string Reason { get; } | |||||
} | |||||
} |
@@ -3,14 +3,7 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Properties that are used to modify an <see cref="IGuildChannel" /> with the specified changes. | /// Properties that are used to modify an <see cref="IGuildChannel" /> with the specified changes. | ||||
/// </summary> | /// </summary> | ||||
/// <example> | |||||
/// <code lang="c#"> | |||||
/// await (Context.Channel as ITextChannel)?.ModifyAsync(x => | |||||
/// { | |||||
/// x.Name = "do-not-enter"; | |||||
/// }); | |||||
/// </code> | |||||
/// </example> | |||||
/// <seealso cref="IGuildChannel.ModifyAsync"/> | |||||
public class GuildChannelProperties | public class GuildChannelProperties | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
@@ -24,7 +24,7 @@ namespace Discord | |||||
/// Gets the parent ID (category) of this channel in the guild's channel list. | /// Gets the parent ID (category) of this channel in the guild's channel list. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
/// The parent category ID associated with this channel, or <see langword="null"/> if none is set. | |||||
/// The parent category ID associated with this channel, or <c>null</c> if none is set. | |||||
/// </returns> | /// </returns> | ||||
ulong? CategoryId { get; } | ulong? CategoryId { get; } | ||||
/// <summary> | /// <summary> | ||||
@@ -57,16 +57,16 @@ namespace Discord | |||||
/// Creates a new invite to this channel. | /// Creates a new invite to this channel. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="maxAge"> | /// <param name="maxAge"> | ||||
/// The time (in seconds) until the invite expires. Set to <see langword="null"/> to never expire. | |||||
/// The time (in seconds) until the invite expires. Set to <c>null</c> to never expire. | |||||
/// </param> | /// </param> | ||||
/// <param name="maxUses"> | /// <param name="maxUses"> | ||||
/// The max amount of times this invite may be used. Set to <see langword="null"/> to have unlimited uses. | |||||
/// The max amount of times this invite may be used. Set to <c>null</c> to have unlimited uses. | |||||
/// </param> | /// </param> | ||||
/// <param name="isTemporary"> | /// <param name="isTemporary"> | ||||
/// If <see langword="true"/>, a user accepting this invite will be kicked from the guild after closing their client. | |||||
/// If <c>true</c>, a user accepting this invite will be kicked from the guild after closing their client. | |||||
/// </param> | /// </param> | ||||
/// <param name="isUnique"> | /// <param name="isUnique"> | ||||
/// If <see langword="true"/>, don't try to reuse a similar invite (useful for creating many unique one time use invites). | |||||
/// If <c>true</c>, don't try to reuse a similar invite (useful for creating many unique one time use invites). | |||||
/// </param> | /// </param> | ||||
/// <param name="options"> | /// <param name="options"> | ||||
/// The options to be used when sending the request. | /// The options to be used when sending the request. | ||||
@@ -86,12 +86,12 @@ namespace Discord | |||||
Task ModifyAsync(Action<GuildChannelProperties> func, RequestOptions options = null); | Task ModifyAsync(Action<GuildChannelProperties> func, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Gets the permission overwrite for a specific role, or <see langword="null"/> if one does not exist. | |||||
/// Gets the permission overwrite for a specific role, or <c>null</c> if one does not exist. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="role">The role to get the overwrite from.</param> | /// <param name="role">The role to get the overwrite from.</param> | ||||
OverwritePermissions? GetPermissionOverwrite(IRole role); | OverwritePermissions? GetPermissionOverwrite(IRole role); | ||||
/// <summary> | /// <summary> | ||||
/// Gets the permission overwrite for a specific user, or <see langword="null"/> if one does not exist. | |||||
/// Gets the permission overwrite for a specific user, or <c>null</c> if one does not exist. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="user">The user to get the overwrite from.</param> | /// <param name="user">The user to get the overwrite from.</param> | ||||
OverwritePermissions? GetPermissionOverwrite(IUser user); | OverwritePermissions? GetPermissionOverwrite(IUser user); | ||||
@@ -17,10 +17,13 @@ namespace Discord | |||||
/// <param name="isTTS">Whether the message should be read aloud by Discord or not.</param> | /// <param name="isTTS">Whether the message should be read aloud by Discord or not.</param> | ||||
/// <param name="embed">The <see cref="EmbedType.Rich"/> <see cref="Embed"/> to be sent.</param> | /// <param name="embed">The <see cref="EmbedType.Rich"/> <see cref="Embed"/> to be sent.</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> | |||||
/// An awaitable Task containing the message sent to the channel. | |||||
/// </returns> | |||||
Task<IUserMessage> SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null); | Task<IUserMessage> SendMessageAsync(string text, bool isTTS = false, Embed embed = null, RequestOptions options = null); | ||||
#if FILESYSTEM | #if FILESYSTEM | ||||
/// <summary> | /// <summary> | ||||
/// Sends a file to this message channel, with an optional caption. | |||||
/// Sends a file to this message channel with an optional caption. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="filePath">The file path of the file.</param> | /// <param name="filePath">The file path of the file.</param> | ||||
/// <param name="text">The message to be sent.</param> | /// <param name="text">The message to be sent.</param> | ||||
@@ -32,10 +35,13 @@ namespace Discord | |||||
/// upload the file and refer to the file with "attachment://filename.ext" in the | /// upload the file and refer to the file with "attachment://filename.ext" in the | ||||
/// <see cref="Discord.EmbedBuilder.ImageUrl"/>. | /// <see cref="Discord.EmbedBuilder.ImageUrl"/>. | ||||
/// </remarks> | /// </remarks> | ||||
/// <returns> | |||||
/// An awaitable Task containing the message sent to the channel. | |||||
/// </returns> | |||||
Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null); | Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null); | ||||
#endif | #endif | ||||
/// <summary> | /// <summary> | ||||
/// Sends a file to this message channel, with an optional caption. | |||||
/// Sends a file to this message channel with an optional caption. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="stream">The <see cref="Stream"/> of the file to be sent.</param> | /// <param name="stream">The <see cref="Stream"/> of the file to be sent.</param> | ||||
/// <param name="filename">The name of the attachment.</param> | /// <param name="filename">The name of the attachment.</param> | ||||
@@ -48,16 +54,19 @@ namespace Discord | |||||
/// upload the file and refer to the file with "attachment://filename.ext" in the | /// upload the file and refer to the file with "attachment://filename.ext" in the | ||||
/// <see cref="Discord.EmbedBuilder.ImageUrl"/>. | /// <see cref="Discord.EmbedBuilder.ImageUrl"/>. | ||||
/// </remarks> | /// </remarks> | ||||
/// <returns> | |||||
/// An awaitable Task containing the message sent to the channel. | |||||
/// </returns> | |||||
Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null); | Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Gets a message from this message channel with the given id, or <see langword="null"/> if not found. | |||||
/// Gets a message from this message channel with the given id, or <c>null</c> if not found. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="id">The ID of the message.</param> | /// <param name="id">The ID of the message.</param> | ||||
/// <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> | ||||
/// The message gotten from either the cache or the download, or <see langword="null"/> if none is found. | |||||
/// The message gotten from either the cache or the download, or <c>null</c> if none is found. | |||||
/// </returns> | /// </returns> | ||||
Task<IMessage> GetMessageAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IMessage> GetMessageAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
@@ -108,7 +117,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 collection of messages. | |||||
/// An awaitable Task containing a collection of messages. | |||||
/// </returns> | /// </returns> | ||||
Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync(RequestOptions options = null); | Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync(RequestOptions options = null); | ||||
@@ -14,7 +14,7 @@ namespace Discord | |||||
/// Determines whether the channel is NSFW. | /// Determines whether the channel is NSFW. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
/// <see langword="true"/> if the channel has the NSFW flag enabled; otherwise, <see langword="false"/>. | |||||
/// <c>true</c> if the channel has the NSFW flag enabled; otherwise, <c>false</c>. | |||||
/// </returns> | /// </returns> | ||||
bool IsNsfw { get; } | bool IsNsfw { get; } | ||||
@@ -22,19 +22,29 @@ namespace Discord | |||||
/// Gets the current topic for this text channel. | /// Gets the current topic for this text channel. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
/// The topic set in the channel, or <see langword="null"/> if none is set. | |||||
/// The topic set in the channel, or <c>null</c> if none is set. | |||||
/// </returns> | /// </returns> | ||||
string Topic { get; } | string Topic { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Bulk-deletes multiple messages. | /// Bulk-deletes multiple messages. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks> | |||||
/// <note type="important"> | |||||
/// This method can only remove messages that are posted within 14 days! | |||||
/// </note> | |||||
/// </remarks> | |||||
/// <param name="messages">The messages to be bulk-deleted.</param> | /// <param name="messages">The messages to be bulk-deleted.</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> | ||||
Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null); | Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Bulk-deletes multiple messages. | /// Bulk-deletes multiple messages. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks> | |||||
/// <note type="important"> | |||||
/// This method can only remove messages that are posted within 14 days! | |||||
/// </note> | |||||
/// </remarks> | |||||
/// <param name="messageIds">The IDs of the messages to be bulk-deleted.</param> | /// <param name="messageIds">The IDs of the messages to be bulk-deleted.</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> | ||||
Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null); | Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null); | ||||
@@ -62,7 +72,7 @@ namespace Discord | |||||
/// <param name="id">The ID of the webhook.</param> | /// <param name="id">The ID of the webhook.</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 webhook associated with the <paramref name="id"/>, or <see langword="null"/> if not found. | |||||
/// A webhook associated with the <paramref name="id"/>, or <c>null</c> if not found. | |||||
/// </returns> | /// </returns> | ||||
Task<IWebhook> GetWebhookAsync(ulong id, RequestOptions options = null); | Task<IWebhook> GetWebhookAsync(ulong id, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
@@ -14,7 +14,7 @@ namespace Discord | |||||
int Bitrate { get; } | int Bitrate { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the max amount of users allowed to be connected to this channel at one time, or | /// Gets the max amount of users allowed to be connected to this channel at one time, or | ||||
/// <see langword="null"/> if none is set. | |||||
/// <c>null</c> if none is set. | |||||
/// </summary> | /// </summary> | ||||
int? UserLimit { get; } | int? UserLimit { get; } | ||||
@@ -1,8 +1,11 @@ | |||||
using System; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Properties that are used to modify an <see cref="ITextChannel"/> with the specified changes. | /// Properties that are used to modify an <see cref="ITextChannel"/> with the specified changes. | ||||
/// </summary> | /// </summary> | ||||
/// <seealso cref="ITextChannel.ModifyAsync(Action{TextChannelProperties}, RequestOptions)"/> | |||||
public class TextChannelProperties : GuildChannelProperties | public class TextChannelProperties : GuildChannelProperties | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
@@ -10,7 +10,7 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
public Optional<int> Bitrate { get; set; } | public Optional<int> Bitrate { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets or sets the maximum number of users that can be present in a channel, or <see langword="null"/> if none. | |||||
/// Gets or sets the maximum number of users that can be present in a channel, or <c>null</c> if none. | |||||
/// </summary> | /// </summary> | ||||
public Optional<int?> UserLimit { get; set; } | public Optional<int?> UserLimit { get; set; } | ||||
} | } | ||||
@@ -5,6 +5,7 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Properties that are used to modify an <see cref="Emote" /> with the specified changes. | /// Properties that are used to modify an <see cref="Emote" /> with the specified changes. | ||||
/// </summary> | /// </summary> | ||||
/// <seealso cref="IGuild.ModifyEmoteAsync"/> | |||||
public class EmoteProperties | public class EmoteProperties | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
@@ -10,11 +10,11 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
public Optional<bool> Enabled { get; set; } | public Optional<bool> Enabled { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// Sets the channel that the invite should place its users in, if not <see langword="null"/>. | |||||
/// Sets the channel that the invite should place its users in, if not <c>null</c>. | |||||
/// </summary> | /// </summary> | ||||
public Optional<IChannel> Channel { get; set; } | public Optional<IChannel> Channel { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// Sets the channel the invite should place its users in, if not <see langword="null"/>. | |||||
/// Sets the channel the invite should place its users in, if not <c>null</c>. | |||||
/// </summary> | /// </summary> | ||||
public Optional<ulong?> ChannelId { get; set; } | public Optional<ulong?> ChannelId { get; set; } | ||||
} | } | ||||
@@ -3,28 +3,19 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Properties that are used to modify an <see cref="IGuild" /> with the specified changes. | /// Properties that are used to modify an <see cref="IGuild" /> with the specified changes. | ||||
/// </summary> | /// </summary> | ||||
/// <example> | |||||
/// <code lang="c#"> | |||||
/// await Context.Guild.ModifyAsync(async x => | |||||
/// { | |||||
/// x.Name = "aaaaaah"; | |||||
/// }); | |||||
/// </code> | |||||
/// </example> | |||||
/// <see cref="T:Discord.IGuild" /> | |||||
/// <see cref="IGuild.ModifyAsync"/> | |||||
public class GuildProperties | public class GuildProperties | ||||
{ | { | ||||
public Optional<string> Username { get; set; } | |||||
/// <summary> | /// <summary> | ||||
/// Gets or sets the name of the Guild. | |||||
/// Gets or sets the name of the guild. Must be within 100 characters. | |||||
/// </summary> | /// </summary> | ||||
public Optional<string> Name { get; set; } | public Optional<string> Name { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets or sets the region for the Guild's voice connections. | |||||
/// Gets or sets the region for the guild's voice connections. | |||||
/// </summary> | /// </summary> | ||||
public Optional<IVoiceRegion> Region { get; set; } | public Optional<IVoiceRegion> Region { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets or sets the ID of the region for the Guild's voice connections. | |||||
/// Gets or sets the ID of the region for the guild's voice connections. | |||||
/// </summary> | /// </summary> | ||||
public Optional<string> RegionId { get; set; } | public Optional<string> RegionId { get; set; } | ||||
/// <summary> | /// <summary> | ||||
@@ -13,17 +13,23 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Gets the name of this guild. | /// Gets the name of this guild. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A string containing the name of this guild. | |||||
/// </returns> | |||||
string Name { get; } | string Name { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the amount of time (in seconds) a user must be inactive in a voice channel for until they are | /// Gets the amount of time (in seconds) a user must be inactive in a voice channel for until they are | ||||
/// automatically moved to the AFK voice channel, if one is set. | |||||
/// automatically moved to the AFK voice channel. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The amount of time in seconds for a user to be marked as inactive and moved into the AFK voice channel. | |||||
/// </returns> | |||||
int AFKTimeout { get; } | int AFKTimeout { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Determines if this guild is embeddable (i.e. can use widget). | /// Determines if this guild is embeddable (i.e. can use widget). | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
/// <see langword="true"/> if this guild can be embedded via widgets; otherwise <see langword="false"/>. | |||||
/// <c>true</c> if this guild can be embedded via widgets; otherwise <c>false</c>. | |||||
/// </returns> | /// </returns> | ||||
bool IsEmbeddable { get; } | bool IsEmbeddable { get; } | ||||
/// <summary> | /// <summary> | ||||
@@ -34,38 +40,61 @@ namespace Discord | |||||
/// Gets the level of Multi-Factor Authentication requirements a user must fulfill before being allowed to | /// Gets the level of Multi-Factor Authentication requirements a user must fulfill before being allowed to | ||||
/// perform administrative actions in this guild. | /// perform administrative actions in this guild. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The level of MFA requirement. | |||||
/// </returns> | |||||
MfaLevel MfaLevel { get; } | MfaLevel MfaLevel { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the level of requirements a user must fulfill before being allowed to post messages in this guild. | /// Gets the level of requirements a user must fulfill before being allowed to post messages in this guild. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The level of requirements. | |||||
/// </returns> | |||||
VerificationLevel VerificationLevel { get; } | VerificationLevel VerificationLevel { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns the ID of this guild's icon, or <see langword="null"/> if none is set. | |||||
/// Gets the ID of this guild's icon. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// An identifier for the splash image; <c>null</c> if none is set. | |||||
/// </returns> | |||||
string IconId { get; } | string IconId { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns the URL of this guild's icon, or <see langword="null"/> if none is set. | |||||
/// Gets the URL of this guild's icon. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A URL pointing to the guild's icon; <c>null</c> if none is set. | |||||
/// </returns> | |||||
string IconUrl { get; } | string IconUrl { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns the ID of this guild's splash image, or <see langword="null"/> if none is set. | |||||
/// Gets the ID of this guild's splash image. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// An identifier for the splash image; <c>null</c> if none is set. | |||||
/// </returns> | |||||
string SplashId { get; } | string SplashId { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns the URL of this guild's splash image, or <see langword="null"/> if none is set. | |||||
/// Gets the URL of this guild's splash image. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A URL pointing to the guild's splash image; <c>null</c> if none is set. | |||||
/// </returns> | |||||
string SplashUrl { get; } | string SplashUrl { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Determines if this guild is currently connected and ready to be used. | /// Determines if this guild is currently connected and ready to be used. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks> | |||||
/// <note> | |||||
/// This property only applies to a WebSocket-based client. | |||||
/// </note> | |||||
/// This boolean is used to determine if the guild is currently connected to the WebSocket and is ready to be used/accessed. | |||||
/// </remarks> | |||||
/// <returns> | /// <returns> | ||||
/// Returns <see langword="true"/> if this guild is currently connected and ready to be used. Only applies | |||||
/// to the WebSocket client. | |||||
/// <c>true</c> if this guild is currently connected and ready to be used; otherwise <c>false</c>. | |||||
/// </returns> | /// </returns> | ||||
bool Available { get; } | bool Available { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the ID of the AFK voice channel for this guild, or <see langword="null"/> if none is set. | |||||
/// Gets the ID of the AFK voice channel for this guild, or <c>null</c> if none is set. | |||||
/// </summary> | /// </summary> | ||||
ulong? AFKChannelId { get; } | ulong? AFKChannelId { get; } | ||||
/// <summary> | /// <summary> | ||||
@@ -73,11 +102,11 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
ulong DefaultChannelId { get; } | ulong DefaultChannelId { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the ID of the embed channel set in the widget settings of this guild, or <see langword="null"/> if none is set. | |||||
/// Gets the ID of the embed channel set in the widget settings of this guild, or <c>null</c> if none is set. | |||||
/// </summary> | /// </summary> | ||||
ulong? EmbedChannelId { get; } | ulong? EmbedChannelId { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the ID of the channel where randomized welcome messages are sent, or <see langword="null"/> if none is set. | |||||
/// Gets the ID of the channel where randomized welcome messages are sent, or <c>null</c> if none is set. | |||||
/// </summary> | /// </summary> | ||||
ulong? SystemChannelId { get; } | ulong? SystemChannelId { get; } | ||||
/// <summary> | /// <summary> | ||||
@@ -143,7 +172,7 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task ModifyEmbedAsync(Action<GuildEmbedProperties> func, RequestOptions options = null); | Task ModifyEmbedAsync(Action<GuildEmbedProperties> func, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Bulk modifies the order of channels in this guild. | |||||
/// Bulk-modifies the order of channels in this guild. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="args">The properties used to modify the channel positions with.</param> | /// <param name="args">The properties used to modify the channel positions with.</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> | ||||
@@ -152,17 +181,21 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task ReorderChannelsAsync(IEnumerable<ReorderChannelProperties> args, RequestOptions options = null); | Task ReorderChannelsAsync(IEnumerable<ReorderChannelProperties> args, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Bulk modifies the order of roles in this guild. | |||||
/// Bulk-modifies the order of roles in this guild. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="args">The properties used to modify the role positions with.</param> | /// <param name="args">The properties used to modify the role positions with.</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> | ||||
Task ReorderRolesAsync(IEnumerable<ReorderRoleProperties> args, RequestOptions options = null); | |||||
/// <returns> | /// <returns> | ||||
/// An awaitable <see cref="Task"/>. | /// An awaitable <see cref="Task"/>. | ||||
/// </returns> | /// </returns> | ||||
Task ReorderRolesAsync(IEnumerable<ReorderRoleProperties> args, RequestOptions options = null); | |||||
/// <summary> | /// <summary> | ||||
/// Leaves this guild. If you are the owner, use <see cref="IDeletable.DeleteAsync" /> instead. | |||||
/// Leaves this guild. | |||||
/// </summary> | /// </summary> | ||||
/// <remarks> | |||||
/// This method will make the currently logged-in user leave the guild. If the user is the owner, use | |||||
/// <see cref="IDeletable.DeleteAsync" /> instead. | |||||
/// </remarks> | |||||
/// <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> | ||||
/// An awaitable <see cref="Task"/>. | /// An awaitable <see cref="Task"/>. | ||||
@@ -178,7 +211,25 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task<IReadOnlyCollection<IBan>> GetBansAsync(RequestOptions options = null); | Task<IReadOnlyCollection<IBan>> GetBansAsync(RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Bans the provided user from this guild and optionally prunes their recent messages. | |||||
/// Gets a ban object for a banned user. | |||||
/// </summary> | |||||
/// <param name="user">The banned user.</param> | |||||
/// <returns> | |||||
/// An awaitable <see cref="Task"/> containing the ban object, which contains the user information and the | |||||
/// reason for the ban; <c>null<c/> if the ban entry cannot be found. | |||||
/// </returns> | |||||
Task<IBan> GetBanAsync(IUser user, RequestOptions options = null); | |||||
/// <summary> | |||||
/// Gets a ban object for a banned user. | |||||
/// </summary> | |||||
/// <param name="userId">The snowflake identifier for the banned user.</param> | |||||
/// <returns> | |||||
/// An awaitable <see cref="Task"/> containing the ban object, which contains the user information and the | |||||
/// reason for the ban; <c>null<c/> if the ban entry cannot be found. | |||||
/// </returns> | |||||
Task<IBan> GetBanAsync(ulong userId, RequestOptions options = null); | |||||
/// <summary> | |||||
/// Bans the user from this guild and optionally prunes their recent messages. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="user">The user to ban.</param> | /// <param name="user">The user to ban.</param> | ||||
/// <param name="pruneDays"> | /// <param name="pruneDays"> | ||||
@@ -192,9 +243,9 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task AddBanAsync(IUser user, int pruneDays = 0, string reason = null, RequestOptions options = null); | Task AddBanAsync(IUser user, int pruneDays = 0, string reason = null, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Bans the provided user ID from this guild and optionally prunes their recent messages. | |||||
/// Bans the user from this guild and optionally prunes their recent messages. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="userId">The ID of the user to ban.</param> | |||||
/// <param name="userId">The snowflake ID of the user to ban.</param> | |||||
/// <param name="pruneDays"> | /// <param name="pruneDays"> | ||||
/// The number of days to remove messages from this user for - must be between [0, 7]. | /// The number of days to remove messages from this user for - must be between [0, 7]. | ||||
/// </param> | /// </param> | ||||
@@ -245,7 +296,7 @@ namespace Discord | |||||
/// <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> | ||||
/// An awaitable <see cref="Task"/> containing the generic channel with the specified ID, or | /// An awaitable <see cref="Task"/> containing the generic channel with the specified ID, or | ||||
/// <see langword="null"/> if none is found. | |||||
/// <c>null</c> if none is found. | |||||
/// </returns> | /// </returns> | ||||
Task<IGuildChannel> GetChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IGuildChannel> GetChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
@@ -260,7 +311,7 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task<IReadOnlyCollection<ITextChannel>> GetTextChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IReadOnlyCollection<ITextChannel>> GetTextChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Gets a text channel in this guild with the provided ID, or <see langword="null" /> if not found. | |||||
/// Gets a text channel in this guild with the provided ID, or <c>null</c> if not found. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="id">The text channel ID.</param> | /// <param name="id">The text channel ID.</param> | ||||
/// <param name="mode"> | /// <param name="mode"> | ||||
@@ -269,7 +320,7 @@ namespace Discord | |||||
/// <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> | ||||
/// An awaitable <see cref="Task"/> containing the text channel with the specified ID, or | /// An awaitable <see cref="Task"/> containing the text channel with the specified ID, or | ||||
/// <see langword="null"/> if none is found. | |||||
/// <c>null</c> if none is found. | |||||
/// </returns> | /// </returns> | ||||
Task<ITextChannel> GetTextChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<ITextChannel> GetTextChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
@@ -304,7 +355,7 @@ namespace Discord | |||||
/// <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> | ||||
/// An awaitable <see cref="Task"/> containing the voice channel with the specified ID, or | /// An awaitable <see cref="Task"/> containing the voice channel with the specified ID, or | ||||
/// <see langword="null"/> if none is found. | |||||
/// <c>null</c> if none is found. | |||||
/// </returns> | /// </returns> | ||||
Task<IVoiceChannel> GetVoiceChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IVoiceChannel> GetVoiceChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
@@ -316,7 +367,7 @@ namespace Discord | |||||
/// <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> | ||||
/// An awaitable <see cref="Task"/> containing the AFK voice channel set within this guild, or | /// An awaitable <see cref="Task"/> containing the AFK voice channel set within this guild, or | ||||
/// <see langword="null"/> if none is set. | |||||
/// <c>null</c> if none is set. | |||||
/// </returns> | /// </returns> | ||||
Task<IVoiceChannel> GetAFKChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IVoiceChannel> GetAFKChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
@@ -328,7 +379,7 @@ namespace Discord | |||||
/// <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> | ||||
/// An awaitable <see cref="Task"/> containing the system channel within this guild, or | /// An awaitable <see cref="Task"/> containing the system channel within this guild, or | ||||
/// <see langword="null" /> if none is set. | |||||
/// <c>null</c> if none is set. | |||||
/// </returns> | /// </returns> | ||||
Task<ITextChannel> GetSystemChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<ITextChannel> GetSystemChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
@@ -340,7 +391,7 @@ namespace Discord | |||||
/// <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> | ||||
/// An awaitable <see cref="Task"/> containing the first viewable text channel in this guild, or | /// An awaitable <see cref="Task"/> containing the first viewable text channel in this guild, or | ||||
/// <see langword="null"/> if none is found. | |||||
/// <c>null</c> if none is found. | |||||
/// </returns> | /// </returns> | ||||
Task<ITextChannel> GetDefaultChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<ITextChannel> GetDefaultChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
@@ -352,7 +403,7 @@ namespace Discord | |||||
/// <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> | ||||
/// An awaitable <see cref="Task"/> containing the embed channel set within the server's widget settings, or | /// An awaitable <see cref="Task"/> containing the embed channel set within the server's widget settings, or | ||||
/// <see langword="null"/> if none is set. | |||||
/// <c>null</c> if none is set. | |||||
/// </returns> | /// </returns> | ||||
Task<IGuildChannel> GetEmbedChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IGuildChannel> GetEmbedChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
@@ -389,12 +440,19 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Gets a collection of all invites to this guild. | /// Gets a collection of all invites to this guild. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// An awaitable <see cref="Task"/> containing a collection of invites found within this guild. | |||||
/// </returns> | |||||
Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null); | Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Gets the role in this guild with the provided ID, or <see langword="null"/> if not found. | |||||
/// Gets a role in this guild. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="id">The role ID.</param> | /// <param name="id">The role ID.</param> | ||||
/// <returns> | |||||
/// A role that matches the provided snowflake identifier; <c>null</c> if none is found. | |||||
/// </returns> | |||||
IRole GetRole(ulong id); | IRole GetRole(ulong id); | ||||
/// <summary> | /// <summary> | ||||
/// Creates a new role with the provided name. | /// Creates a new role with the provided name. | ||||
@@ -412,25 +470,30 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Gets a collection of all users in this guild. | /// Gets a collection of all users in this guild. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from | |||||
/// cache.</param> | |||||
/// <remarks> | |||||
/// This method retrieves all users found within this guild. | |||||
/// <note> | |||||
/// This may return an incomplete list on the WebSocket implementation. | |||||
/// </note> | |||||
/// </remarks> | |||||
/// <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> | ||||
/// An awaitable <see cref="Task"/> containing a collection of users found within this guild. | /// An awaitable <see cref="Task"/> containing a collection of users found within this guild. | ||||
/// </returns> | /// </returns> | ||||
/// <remarks> | |||||
/// This may return an incomplete list on the WebSocket implementation because Discord only sends offline | |||||
/// users on large guilds. | |||||
/// </remarks> | |||||
Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Gets the user in this guild with the provided ID, or <see langword="null"/> if not found. | |||||
/// Gets a user found in this guild. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="id">The user ID.</param> | |||||
/// <param name="mode">The <see cref="CacheMode"/> that determines whether the object should be fetched from cache.</param> | |||||
/// <param name="id">The user ID to search for.</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> | ||||
/// An awaitable <see cref="Task"/> containing the guild user with the specified ID, otherwise <see langword="null"/>. | |||||
/// An awaitable <see cref="Task"/> containing the guild user with the specified ID; <c>null</c> if none is | |||||
/// found. | |||||
/// </returns> | /// </returns> | ||||
Task<IGuildUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IGuildUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
@@ -459,25 +522,33 @@ namespace Discord | |||||
/// </returns> | /// </returns> | ||||
Task DownloadUsersAsync(); | Task DownloadUsersAsync(); | ||||
/// <summary> | /// <summary> | ||||
/// Removes all users from this guild if they have not logged on in a provided number of | |||||
/// <paramref name="days" /> or, if <paramref name="simulate" /> is <see langword="true"/>, returns the | |||||
/// number of users that would be removed. | |||||
/// Prunes inactive users. | |||||
/// </summary> | /// </summary> | ||||
/// <remarks> | |||||
/// This method removes all users that have not logged on in the provided number of days or, if | |||||
/// <paramref name="simulate"/> is <c>true</c>, returns the number of users that would be removed. | |||||
/// </remarks> | |||||
/// <param name="days">The number of days required for the users to be kicked.</param> | /// <param name="days">The number of days required for the users to be kicked.</param> | ||||
/// <param name="simulate">Whether this prune action is a simulation.</param> | /// <param name="simulate">Whether this prune action is a simulation.</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> | ||||
/// An awaitable <see cref="Task"/> containing the number of users to be or has been removed from this guild. | |||||
/// An awaitable <see cref="Task" /> containing the number of users to be or has been removed from this | |||||
/// guild. | |||||
/// </returns> | /// </returns> | ||||
Task<int> PruneUsersAsync(int days = 30, bool simulate = false, RequestOptions options = null); | Task<int> PruneUsersAsync(int days = 30, bool simulate = false, RequestOptions options = null); | ||||
/// <summary> Gets the specified number of audit log entries for this guild. </summary> | |||||
Task<IReadOnlyCollection<IAuditLogEntry>> GetAuditLogAsync(int limit = DiscordConfig.MaxAuditLogEntriesPerBatch, | |||||
CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | |||||
/// <summary> | /// <summary> | ||||
/// Gets the webhook in this guild with the provided ID, or <see langword="null"/> if not found. | |||||
/// Gets a webhook found within this guild. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="id">The webhook ID.</param> | /// <param name="id">The webhook ID.</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> | ||||
/// An awaitable <see cref="Task"/> containing the webhook with the specified ID, otherwise <see langword="null"/>. | |||||
/// An awaitable <see cref="Task"/> containing the webhook with the specified ID; <c>null</c> if none is | |||||
/// found. | |||||
/// </returns> | /// </returns> | ||||
Task<IWebhook> GetWebhookAsync(ulong id, RequestOptions options = null); | Task<IWebhook> GetWebhookAsync(ulong id, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
@@ -495,7 +566,8 @@ namespace Discord | |||||
/// <param name="id">The guild emote ID.</param> | /// <param name="id">The guild emote ID.</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> | ||||
/// An awaitable <see cref="Task"/> containing the emote found with the specified ID, or <see langword="null"/> if not found. | |||||
/// An awaitable <see cref="Task"/> containing the emote found with the specified ID; <c>null</c> if none is | |||||
/// found. | |||||
/// </returns> | /// </returns> | ||||
Task<GuildEmote> GetEmoteAsync(ulong id, RequestOptions options = null); | Task<GuildEmote> GetEmoteAsync(ulong id, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
@@ -7,11 +7,11 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
string Name { get; } | string Name { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the icon URL associated with this guild, or <see langword="null"/> if one is not set. | |||||
/// Gets the icon URL associated with this guild, or <c>null</c> if one is not set. | |||||
/// </summary> | /// </summary> | ||||
string IconUrl { get; } | string IconUrl { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if the current user owns this guild. | |||||
/// Returns <c>true</c> if the current user owns this guild. | |||||
/// </summary> | /// </summary> | ||||
bool IsOwner { get; } | bool IsOwner { get; } | ||||
/// <summary> | /// <summary> | ||||
@@ -14,19 +14,19 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
string Name { get; } | string Name { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if this voice region is exclusive to VIP accounts. | |||||
/// Returns <c>true</c> if this voice region is exclusive to VIP accounts. | |||||
/// </summary> | /// </summary> | ||||
bool IsVip { get; } | bool IsVip { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if this voice region is the closest to your machine. | |||||
/// Returns <c>true</c> if this voice region is the closest to your machine. | |||||
/// </summary> | /// </summary> | ||||
bool IsOptimal { get; } | bool IsOptimal { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if this is a deprecated voice region (avoid switching to these). | |||||
/// Returns <c>true</c> if this is a deprecated voice region (avoid switching to these). | |||||
/// </summary> | /// </summary> | ||||
bool IsDeprecated { get; } | bool IsDeprecated { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if this is a custom voice region (used for events/etc). | |||||
/// Returns <c>true</c> if this is a custom voice region (used for events/etc). | |||||
/// </summary> | /// </summary> | ||||
bool IsCustom { get; } | bool IsCustom { get; } | ||||
} | } | ||||
@@ -35,7 +35,7 @@ namespace Discord | |||||
/// <paramref name="path" /> is a zero-length string, contains only white space, or contains one or more invalid | /// <paramref name="path" /> is a zero-length string, contains only white space, or contains one or more invalid | ||||
/// characters as defined by <see cref="Path.GetInvalidPathChars" />. | /// characters as defined by <see cref="Path.GetInvalidPathChars" />. | ||||
/// </exception> | /// </exception> | ||||
/// <exception cref="ArgumentNullException"><paramref name="path" /> is <see langword="null" />.</exception> | |||||
/// <exception cref="ArgumentNullException"><paramref name="path" /> is <c>null</c>.</exception> | |||||
/// <exception cref="PathTooLongException"> | /// <exception cref="PathTooLongException"> | ||||
/// The specified path, file name, or both exceed the system-defined maximum length. For example, on | /// The specified path, file name, or both exceed the system-defined maximum length. For example, on | ||||
/// Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 | /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 | ||||
@@ -10,20 +10,20 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
IUser Inviter { get; } | IUser Inviter { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if this invite was revoked. | |||||
/// Returns <c>true</c> if this invite was revoked. | |||||
/// </summary> | /// </summary> | ||||
bool IsRevoked { get; } | bool IsRevoked { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if users accepting this invite will be removed from the guild when they | |||||
/// Returns <c>true</c> if users accepting this invite will be removed from the guild when they | |||||
/// log off. | /// log off. | ||||
/// </summary> | /// </summary> | ||||
bool IsTemporary { get; } | bool IsTemporary { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the time (in seconds) until the invite expires, or <see langword="null"/> if it never expires. | |||||
/// Gets the time (in seconds) until the invite expires, or <c>null</c> if it never expires. | |||||
/// </summary> | /// </summary> | ||||
int? MaxAge { get; } | int? MaxAge { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the max amount of times this invite may be used, or <see langword="null"/> if there is no limit. | |||||
/// Gets the max amount of times this invite may be used, or <c>null</c> if there is no limit. | |||||
/// </summary> | /// </summary> | ||||
int? MaxUses { get; } | int? MaxUses { get; } | ||||
/// <summary> | /// <summary> | ||||
@@ -3,7 +3,7 @@ using System.Diagnostics; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Represents a author field of an <see cref="Embed" />. | |||||
/// A author field of an <see cref="Embed" />. | |||||
/// </summary> | /// </summary> | ||||
[DebuggerDisplay("{DebuggerDisplay,nq}")] | [DebuggerDisplay("{DebuggerDisplay,nq}")] | ||||
public struct EmbedAuthor | public struct EmbedAuthor | ||||
@@ -106,7 +106,7 @@ namespace Discord | |||||
/// <summary> Gets or sets the list of <see cref="EmbedFieldBuilder"/> of an <see cref="Embed"/>. </summary> | /// <summary> Gets or sets the list of <see cref="EmbedFieldBuilder"/> of an <see cref="Embed"/>. </summary> | ||||
/// <exception cref="ArgumentNullException" accessor="set">An embed builder's fields collection is set to | /// <exception cref="ArgumentNullException" accessor="set">An embed builder's fields collection is set to | ||||
/// <see langword="null"/>.</exception> | |||||
/// <c>null</c>.</exception> | |||||
/// <exception cref="ArgumentException" accessor="set">Description length exceeds <see cref="MaxFieldCount"/>. | /// <exception cref="ArgumentException" accessor="set">Description length exceeds <see cref="MaxFieldCount"/>. | ||||
/// </exception> | /// </exception> | ||||
/// <returns> The list of existing <see cref="EmbedFieldBuilder"/>.</returns> | /// <returns> The list of existing <see cref="EmbedFieldBuilder"/>.</returns> | ||||
@@ -125,28 +125,28 @@ namespace Discord | |||||
/// Gets or sets the timestamp of an <see cref="Embed" />. | /// Gets or sets the timestamp of an <see cref="Embed" />. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
/// The timestamp of the embed, or <see langword="null" /> if none is set. | |||||
/// The timestamp of the embed, or <c>null</c> if none is set. | |||||
/// </returns> | /// </returns> | ||||
public DateTimeOffset? Timestamp { get; set; } | public DateTimeOffset? Timestamp { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets or sets the sidebar color of an <see cref="Embed" />. | /// Gets or sets the sidebar color of an <see cref="Embed" />. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
/// The color of the embed, or <see langword="null" /> if none is set. | |||||
/// The color of the embed, or <c>null</c> if none is set. | |||||
/// </returns> | /// </returns> | ||||
public Color? Color { get; set; } | public Color? Color { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets or sets the <see cref="EmbedAuthorBuilder" /> of an <see cref="Embed" />. | /// Gets or sets the <see cref="EmbedAuthorBuilder" /> of an <see cref="Embed" />. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
/// The author field builder of the embed, or <see langword="null" /> if none is set. | |||||
/// The author field builder of the embed, or <c>null</c> if none is set. | |||||
/// </returns> | /// </returns> | ||||
public EmbedAuthorBuilder Author { get; set; } | public EmbedAuthorBuilder Author { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets or sets the <see cref="EmbedFooterBuilder" /> of an <see cref="Embed" />. | /// Gets or sets the <see cref="EmbedFooterBuilder" /> of an <see cref="Embed" />. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
/// The footer field builder of the embed, or <see langword="null" /> if none is set. | |||||
/// The footer field builder of the embed, or <c>null</c> if none is set. | |||||
/// </returns> | /// </returns> | ||||
public EmbedFooterBuilder Footer { get; set; } | public EmbedFooterBuilder Footer { get; set; } | ||||
@@ -438,7 +438,6 @@ namespace Discord | |||||
{ | { | ||||
private string _name; | private string _name; | ||||
private string _value; | private string _value; | ||||
private EmbedField _field; | |||||
/// <summary> | /// <summary> | ||||
/// Gets the maximum field length for name allowed by Discord. | /// Gets the maximum field length for name allowed by Discord. | ||||
/// </summary> | /// </summary> | ||||
@@ -452,7 +451,7 @@ namespace Discord | |||||
/// Gets or sets the field name. | /// Gets or sets the field name. | ||||
/// </summary> | /// </summary> | ||||
/// <exception cref="ArgumentException"> | /// <exception cref="ArgumentException"> | ||||
/// <para>Field name is <see langword="null" />, empty or entirely whitespace.</para> | |||||
/// <para>Field name is <c>null</c>, empty or entirely whitespace.</para> | |||||
/// <para><c>- or -</c></para> | /// <para><c>- or -</c></para> | ||||
/// <para>Field name length exceeds <see cref="MaxFieldNameLength"/>.</para> | /// <para>Field name length exceeds <see cref="MaxFieldNameLength"/>.</para> | ||||
/// </exception> | /// </exception> | ||||
@@ -474,7 +473,7 @@ namespace Discord | |||||
/// Gets or sets the field value. | /// Gets or sets the field value. | ||||
/// </summary> | /// </summary> | ||||
/// <exception cref="ArgumentException" accessor="set"> | /// <exception cref="ArgumentException" accessor="set"> | ||||
/// <para>Field value is <see langword="null" />, empty or entirely whitespace.</para> | |||||
/// <para>Field value is <c>null</c>, empty or entirely whitespace.</para> | |||||
/// <para><c>- or -</c></para> | /// <para><c>- or -</c></para> | ||||
/// <para>Field value length exceeds <see cref="MaxFieldValueLength"/>.</para> | /// <para>Field value length exceeds <see cref="MaxFieldValueLength"/>.</para> | ||||
/// </exception> | /// </exception> | ||||
@@ -540,7 +539,7 @@ namespace Discord | |||||
/// The current builder. | /// The current builder. | ||||
/// </returns> | /// </returns> | ||||
/// <exception cref="ArgumentException"> | /// <exception cref="ArgumentException"> | ||||
/// <para><see cref="Name"/> or <see cref="Value"/> is <see langword="null" />, empty or entirely whitespace.</para> | |||||
/// <para><see cref="Name"/> or <see cref="Value"/> is <c>null</c>, empty or entirely whitespace.</para> | |||||
/// <para><c>- or -</c></para> | /// <para><c>- or -</c></para> | ||||
/// <para><see cref="Name"/> or <see cref="Value"/> exceeds the maximum length allowed by Discord.</para> | /// <para><see cref="Name"/> or <see cref="Value"/> exceeds the maximum length allowed by Discord.</para> | ||||
/// </exception> | /// </exception> | ||||
@@ -3,7 +3,7 @@ using System.Diagnostics; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Represents a field for an <see cref="Embed" />. | |||||
/// A field for an <see cref="Embed" />. | |||||
/// </summary> | /// </summary> | ||||
[DebuggerDisplay("{DebuggerDisplay,nq}")] | [DebuggerDisplay("{DebuggerDisplay,nq}")] | ||||
public struct EmbedField | public struct EmbedField | ||||
@@ -13,11 +13,11 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
public string Url { get; } | public string Url { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the height of the video, or <see langword="null"/> if none. | |||||
/// Gets the height of the video, or <c>null</c> if none. | |||||
/// </summary> | /// </summary> | ||||
public int? Height { get; } | public int? Height { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the weight of the video, or <see langword="null"/> if none. | |||||
/// Gets the weight of the video, or <c>null</c> if none. | |||||
/// </summary> | /// </summary> | ||||
public int? Width { get; } | public int? Width { get; } | ||||
@@ -6,33 +6,54 @@ namespace Discord | |||||
public interface IAttachment | public interface IAttachment | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Gets the snowflake ID of the attachment. | |||||
/// Gets the ID of this attachment. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A snowflake ID associated with this attachment. | |||||
/// </returns> | |||||
ulong Id { get; } | ulong Id { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the filename of the attachment. | |||||
/// Gets the filename of this attachment. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A string containing the full filename of this attachment (e.g. textFile.txt). | |||||
/// </returns> | |||||
string Filename { get; } | string Filename { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the URL of the attachment. | |||||
/// Gets the URL of this attachment. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A string containing the URL of this attachment. | |||||
/// </returns> | |||||
string Url { get; } | string Url { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the proxied URL of the attachment. | |||||
/// Gets a proxied URL of this attachment. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A string containing the proxied URL of this attachment. | |||||
/// </returns> | |||||
string ProxyUrl { get; } | string ProxyUrl { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the file size of the attachment. | |||||
/// Gets the file size of this attachment. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The size of this attachment in bytes. | |||||
/// </returns> | |||||
int Size { get; } | int Size { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the height of the attachment if it is an image, or return <see langword="null" /> when it is not. | |||||
/// Gets the height of this attachment. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The height of this attachment if it is a picture; otherwise <c>null</c>. | |||||
/// </returns> | |||||
int? Height { get; } | int? Height { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the width of the attachment if it is an image, or return <see langword="null" /> when it is not. | |||||
/// Gets the width of this attachment. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The width of this attachment if it is a picture; otherwise <c>null</c>. | |||||
/// </returns> | |||||
int? Width { get; } | int? Width { get; } | ||||
} | } | ||||
} | } |
@@ -9,56 +9,96 @@ namespace Discord | |||||
public interface IEmbed | public interface IEmbed | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Gets the title URL of the embed. | |||||
/// Gets the title URL of this embed. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A string containing the URL set in a title of the embed. | |||||
/// </returns> | |||||
string Url { get; } | string Url { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the title of the embed. | |||||
/// Gets the title of this embed. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The title of the embed. | |||||
/// </returns> | |||||
string Title { get; } | string Title { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the description of the embed. | |||||
/// Gets the description of this embed. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The description field of the embed. | |||||
/// </returns> | |||||
string Description { get; } | string Description { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the type of the embed. | |||||
/// Gets the type of this embed. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The type of the embed. | |||||
/// </returns> | |||||
EmbedType Type { get; } | EmbedType Type { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the timestamp of the embed, or <see langword="null" /> if none is set. | |||||
/// Gets the timestamp of this embed. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A <see cref="DateTimeOffset"/> based on the timestamp present at the bottom left of the embed, or | |||||
/// <c>null</c> if none is set. | |||||
/// </returns> | |||||
DateTimeOffset? Timestamp { get; } | DateTimeOffset? Timestamp { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the sidebar color of the embed, or <see langword="null" /> if none is set. | |||||
/// Gets the color of this embed. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The color of the embed present on the side of the embed, or <c>null</c> if none is set. | |||||
/// </returns> | |||||
Color? Color { get; } | Color? Color { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the image of the embed, or <see langword="null" /> if none is set. | |||||
/// Gets the image of this embed. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The image of the embed, or <c>null</c> if none is set. | |||||
/// </returns> | |||||
EmbedImage? Image { get; } | EmbedImage? Image { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the video of the embed, or <see langword="null" /> if none is set. | |||||
/// Gets the video of this embed. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The video of the embed, or <c>null</c> if none is set. | |||||
/// </returns> | |||||
EmbedVideo? Video { get; } | EmbedVideo? Video { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the author field of the embed, or <see langword="null" /> if none is set. | |||||
/// Gets the author field of this embed. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The author field of the embed, or <c>null</c> if none is set. | |||||
/// </returns> | |||||
EmbedAuthor? Author { get; } | EmbedAuthor? Author { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the footer field of the embed, or <see langword="null" /> if none is set. | |||||
/// Gets the footer field of this embed. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The author field of the embed, or <c>null</c> if none is set. | |||||
/// </returns> | |||||
EmbedFooter? Footer { get; } | EmbedFooter? Footer { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the provider of the embed, or <see langword="null" /> if none is set. | |||||
/// Gets the provider of this embed. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The source of the embed, or <c>null</c> if none is set. | |||||
/// </returns> | |||||
EmbedProvider? Provider { get; } | EmbedProvider? Provider { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the thumbnail featured in the embed, or <see langword="null" /> if none is set. | |||||
/// Gets the thumbnail featured in this embed. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// The thumbnail featured in the embed, or <c>null</c> if none is set. | |||||
/// </returns> | |||||
EmbedThumbnail? Thumbnail { get; } | EmbedThumbnail? Thumbnail { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the fields of the embed. | /// Gets the fields of the embed. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// An array of the fields of the embed. | |||||
/// </returns> | |||||
ImmutableArray<EmbedField> Fields { get; } | ImmutableArray<EmbedField> Fields { get; } | ||||
} | } | ||||
} | } |
@@ -17,11 +17,11 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
MessageSource Source { get; } | MessageSource Source { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if this message was sent as a text-to-speech message. | |||||
/// Returns <c>true</c> if this message was sent as a text-to-speech message. | |||||
/// </summary> | /// </summary> | ||||
bool IsTTS { get; } | bool IsTTS { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if this message was added to its channel's pinned messages. | |||||
/// Returns <c>true</c> if this message was added to its channel's pinned messages. | |||||
/// </summary> | /// </summary> | ||||
bool IsPinned { get; } | bool IsPinned { get; } | ||||
/// <summary> | /// <summary> | ||||
@@ -31,14 +31,20 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Gets the time this message was sent. | /// Gets the time this message was sent. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// Time of when the message was sent. | |||||
/// </returns> | |||||
DateTimeOffset Timestamp { get; } | DateTimeOffset Timestamp { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the time of this message's last edit, or <see langword="null" /> if none is set. | |||||
/// Gets the time of this message's last edit. | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// Time of when the message was last edited; <c>null</c> when the message is never edited. | |||||
/// </returns> | |||||
DateTimeOffset? EditedTimestamp { get; } | DateTimeOffset? EditedTimestamp { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the channel this message was sent to. | |||||
/// Gets the source channel of the message. | |||||
/// </summary> | /// </summary> | ||||
IMessageChannel Channel { get; } | IMessageChannel Channel { get; } | ||||
/// <summary> | /// <summary> | ||||
@@ -49,10 +55,16 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Returns all attachments included in this message. | /// Returns all attachments included in this message. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// Collection of attachments. | |||||
/// </returns> | |||||
IReadOnlyCollection<IAttachment> Attachments { get; } | IReadOnlyCollection<IAttachment> Attachments { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns all embeds included in this message. | /// Returns all embeds included in this message. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// Collection of embed objects. | |||||
/// </returns> | |||||
IReadOnlyCollection<IEmbed> Embeds { get; } | IReadOnlyCollection<IEmbed> Embeds { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns all tags included in this message's content. | /// Returns all tags included in this message's content. | ||||
@@ -61,14 +73,23 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Returns the IDs of channels mentioned in this message. | /// Returns the IDs of channels mentioned in this message. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// Collection of channel IDs. | |||||
/// </returns> | |||||
IReadOnlyCollection<ulong> MentionedChannelIds { get; } | IReadOnlyCollection<ulong> MentionedChannelIds { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns the IDs of roles mentioned in this message. | /// Returns the IDs of roles mentioned in this message. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// Collection of role IDs. | |||||
/// </returns> | |||||
IReadOnlyCollection<ulong> MentionedRoleIds { get; } | IReadOnlyCollection<ulong> MentionedRoleIds { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns the IDs of users mentioned in this message. | /// Returns the IDs of users mentioned in this message. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// Collection of user IDs. | |||||
/// </returns> | |||||
IReadOnlyCollection<ulong> MentionedUserIds { get; } | IReadOnlyCollection<ulong> MentionedUserIds { get; } | ||||
} | } | ||||
} | } |
@@ -1,7 +1,7 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Represents a message sent by the system. | |||||
/// Represents a generic message sent by the system. | |||||
/// </summary> | /// </summary> | ||||
public interface ISystemMessage : IMessage | public interface ISystemMessage : IMessage | ||||
{ | { | ||||
@@ -5,7 +5,7 @@ using System.Threading.Tasks; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Represents a Discord message object. | |||||
/// Represents a generic message sent by a user. | |||||
/// </summary> | /// </summary> | ||||
public interface IUserMessage : IMessage | public interface IUserMessage : IMessage | ||||
{ | { | ||||
@@ -4,23 +4,9 @@ namespace Discord | |||||
/// Properties that are used to modify an <see cref="IUserMessage" /> with the specified changes. | /// Properties that are used to modify an <see cref="IUserMessage" /> with the specified changes. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks> | /// <remarks> | ||||
/// The content of a message can be cleared with <see cref="string.Empty"/> if and only if an <see cref="Discord.Embed"/> is present. | |||||
/// The content of a message can be cleared with <see cref="System.String.Empty"/> if and only if an <see cref="Discord.Embed"/> is present. | |||||
/// </remarks> | /// </remarks> | ||||
/// <example> | |||||
/// <code lang="c#"> | |||||
/// var message = await ReplyAsync("abc"); | |||||
/// await message.ModifyAsync(x => | |||||
/// { | |||||
/// x.Content = ""; | |||||
/// x.Embed = new EmbedBuilder() | |||||
/// .WithColor(new Color(40, 40, 120)) | |||||
/// .WithAuthor(a => a.Name = "foxbot") | |||||
/// .WithTitle("Embed!") | |||||
/// .WithDescription("This is an embed.") | |||||
/// .Build(); | |||||
/// }); | |||||
/// </code> | |||||
/// </example> | |||||
/// <seealso cref="IUserMessage.ModifyAsync"/> | |||||
public class MessageProperties | public class MessageProperties | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
@@ -11,7 +11,7 @@ namespace Discord | |||||
public int ReactionCount { get; internal set; } | public int ReactionCount { get; internal set; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if the current user has used this reaction. | |||||
/// Returns <c>true</c> if the current user has used this reaction. | |||||
/// </summary> | /// </summary> | ||||
public bool IsMe { get; internal set; } | public bool IsMe { get; internal set; } | ||||
} | } | ||||
@@ -1,21 +1,39 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
/// <summary> Specifies the handling type the tag should use. </summary> | |||||
/// <summary> | |||||
/// Specifies the handling type the tag should use. | |||||
/// </summary> | |||||
/// <seealso cref="MentionUtils"/> | |||||
/// <seealso cref="IUserMessage.Resolve"/> | |||||
public enum TagHandling | public enum TagHandling | ||||
{ | { | ||||
/// <summary> Tag handling is ignored. </summary> | |||||
Ignore = 0, //<@53905483156684800> -> <@53905483156684800> | |||||
/// <summary> Removes the tag entirely. </summary> | |||||
Remove, //<@53905483156684800> -> | |||||
/// <summary> Resolves to username (e.g. @User). </summary> | |||||
Name, //<@53905483156684800> -> @Voltana | |||||
/// <summary> Resolves to username without mention prefix (e.g. User). </summary> | |||||
NameNoPrefix, //<@53905483156684800> -> Voltana | |||||
/// <summary> Resolves to username with discriminator value. (e.g. @User#0001). </summary> | |||||
FullName, //<@53905483156684800> -> @Voltana#8252 | |||||
/// <summary> Resolves to username with discriminator value without mention prefix. (e.g. User#0001). </summary> | |||||
FullNameNoPrefix, //<@53905483156684800> -> Voltana#8252 | |||||
/// <summary> Sanitizes the tag. </summary> | |||||
Sanitize //<@53905483156684800> -> <@53905483156684800> (w/ nbsp) | |||||
/// <summary> | |||||
/// Tag handling is ignored (e.g. <@53905483156684800> -> <@53905483156684800>). | |||||
/// </summary> | |||||
Ignore = 0, | |||||
/// <summary> | |||||
/// Removes the tag entirely. | |||||
/// </summary> | |||||
Remove, | |||||
/// <summary> | |||||
/// Resolves to username (e.g. <@53905483156684800> -> @Voltana). | |||||
/// </summary> | |||||
Name, | |||||
/// <summary> | |||||
/// Resolves to username without mention prefix (e.g. <@53905483156684800> -> Voltana). | |||||
/// </summary> | |||||
NameNoPrefix, | |||||
/// <summary> | |||||
/// Resolves to username with discriminator value. (e.g. <@53905483156684800> -> @Voltana#8252). | |||||
/// </summary> | |||||
FullName, | |||||
/// <summary> | |||||
/// Resolves to username with discriminator value without mention prefix. (e.g. <@53905483156684800> -> Voltana#8252). | |||||
/// </summary> | |||||
FullNameNoPrefix, | |||||
/// <summary> | |||||
/// Sanitizes the tag (e.g. <@53905483156684800> -> <@53905483156684800> (w/ nbsp)). | |||||
/// </summary> | |||||
Sanitize | |||||
} | } | ||||
} | } |
@@ -12,7 +12,7 @@ namespace Discord | |||||
/// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for text channels. </summary> | /// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for text channels. </summary> | ||||
public static readonly ChannelPermissions Text = new ChannelPermissions(0b01100_0000000_1111111110001_010001); | public static readonly ChannelPermissions Text = new ChannelPermissions(0b01100_0000000_1111111110001_010001); | ||||
/// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for voice channels. </summary> | /// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for voice channels. </summary> | ||||
public static readonly ChannelPermissions Voice = new ChannelPermissions(0b00100_1111110_0000000000000_010001); | |||||
public static readonly ChannelPermissions Voice = new ChannelPermissions(0b00100_1111110_0000000010000_010001); | |||||
/// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for category channels. </summary> | /// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for category channels. </summary> | ||||
public static readonly ChannelPermissions Category = new ChannelPermissions(0b01100_1111110_1111111110001_010001); | public static readonly ChannelPermissions Category = new ChannelPermissions(0b01100_1111110_1111111110001_010001); | ||||
/// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for direct message channels. </summary> | /// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for direct message channels. </summary> | ||||
@@ -37,52 +37,52 @@ namespace Discord | |||||
/// <summary> Gets a packed value representing all the permissions in this <see cref="ChannelPermissions"/>. </summary> | /// <summary> Gets a packed value representing all the permissions in this <see cref="ChannelPermissions"/>. </summary> | ||||
public ulong RawValue { get; } | public ulong RawValue { get; } | ||||
/// <summary> If <see langword="true"/>, a user may create invites. </summary> | |||||
/// <summary> If <c>true</c>, a user may create invites. </summary> | |||||
public bool CreateInstantInvite => Permissions.GetValue(RawValue, ChannelPermission.CreateInstantInvite); | public bool CreateInstantInvite => Permissions.GetValue(RawValue, ChannelPermission.CreateInstantInvite); | ||||
/// <summary> If <see langword="true"/>, a user may create, delete and modify this channel. </summary> | |||||
/// <summary> If <c>true</c>, a user may create, delete and modify this channel. </summary> | |||||
public bool ManageChannel => Permissions.GetValue(RawValue, ChannelPermission.ManageChannels); | public bool ManageChannel => Permissions.GetValue(RawValue, ChannelPermission.ManageChannels); | ||||
/// <summary> If <see langword="true"/>, a user may add reactions. </summary> | |||||
/// <summary> If <c>true</c>, a user may add reactions. </summary> | |||||
public bool AddReactions => Permissions.GetValue(RawValue, ChannelPermission.AddReactions); | public bool AddReactions => Permissions.GetValue(RawValue, ChannelPermission.AddReactions); | ||||
/// <summary> If <see langword="true"/>, a user may join channels. </summary> | |||||
/// <summary> If <c>true</c>, a user may join channels. </summary> | |||||
[Obsolete("Use ViewChannel instead.")] | [Obsolete("Use ViewChannel instead.")] | ||||
public bool ReadMessages => ViewChannel; | public bool ReadMessages => ViewChannel; | ||||
/// <summary> If <see langword="true"/>, a user may view channels. </summary> | |||||
/// <summary> If <c>true</c>, a user may view channels. </summary> | |||||
public bool ViewChannel => Permissions.GetValue(RawValue, ChannelPermission.ViewChannel); | public bool ViewChannel => Permissions.GetValue(RawValue, ChannelPermission.ViewChannel); | ||||
/// <summary> If <see langword="true"/>, a user may send messages. </summary> | |||||
/// <summary> If <c>true</c>, a user may send messages. </summary> | |||||
public bool SendMessages => Permissions.GetValue(RawValue, ChannelPermission.SendMessages); | public bool SendMessages => Permissions.GetValue(RawValue, ChannelPermission.SendMessages); | ||||
/// <summary> If <see langword="true"/>, a user may send text-to-speech messages. </summary> | |||||
/// <summary> If <c>true</c>, a user may send text-to-speech messages. </summary> | |||||
public bool SendTTSMessages => Permissions.GetValue(RawValue, ChannelPermission.SendTTSMessages); | public bool SendTTSMessages => Permissions.GetValue(RawValue, ChannelPermission.SendTTSMessages); | ||||
/// <summary> If <see langword="true"/>, a user may delete messages. </summary> | |||||
/// <summary> If <c>true</c>, a user may delete messages. </summary> | |||||
public bool ManageMessages => Permissions.GetValue(RawValue, ChannelPermission.ManageMessages); | public bool ManageMessages => Permissions.GetValue(RawValue, ChannelPermission.ManageMessages); | ||||
/// <summary> If <see langword="true"/>, Discord will auto-embed links sent by this user. </summary> | |||||
/// <summary> If <c>true</c>, Discord will auto-embed links sent by this user. </summary> | |||||
public bool EmbedLinks => Permissions.GetValue(RawValue, ChannelPermission.EmbedLinks); | public bool EmbedLinks => Permissions.GetValue(RawValue, ChannelPermission.EmbedLinks); | ||||
/// <summary> If <see langword="true"/>, a user may send files. </summary> | |||||
/// <summary> If <c>true</c>, a user may send files. </summary> | |||||
public bool AttachFiles => Permissions.GetValue(RawValue, ChannelPermission.AttachFiles); | public bool AttachFiles => Permissions.GetValue(RawValue, ChannelPermission.AttachFiles); | ||||
/// <summary> If <see langword="true"/>, a user may read previous messages. </summary> | |||||
/// <summary> If <c>true</c>, a user may read previous messages. </summary> | |||||
public bool ReadMessageHistory => Permissions.GetValue(RawValue, ChannelPermission.ReadMessageHistory); | public bool ReadMessageHistory => Permissions.GetValue(RawValue, ChannelPermission.ReadMessageHistory); | ||||
/// <summary> If <see langword="true"/>, a user may mention @everyone. </summary> | |||||
/// <summary> If <c>true</c>, a user may mention @everyone. </summary> | |||||
public bool MentionEveryone => Permissions.GetValue(RawValue, ChannelPermission.MentionEveryone); | public bool MentionEveryone => Permissions.GetValue(RawValue, ChannelPermission.MentionEveryone); | ||||
/// <summary> If <see langword="true"/>, a user may use custom emoji from other guilds. </summary> | |||||
/// <summary> If <c>true</c>, a user may use custom emoji from other guilds. </summary> | |||||
public bool UseExternalEmojis => Permissions.GetValue(RawValue, ChannelPermission.UseExternalEmojis); | public bool UseExternalEmojis => Permissions.GetValue(RawValue, ChannelPermission.UseExternalEmojis); | ||||
/// <summary> If <see langword="true"/>, a user may connect to a voice channel. </summary> | |||||
/// <summary> If <c>true</c>, a user may connect to a voice channel. </summary> | |||||
public bool Connect => Permissions.GetValue(RawValue, ChannelPermission.Connect); | public bool Connect => Permissions.GetValue(RawValue, ChannelPermission.Connect); | ||||
/// <summary> If <see langword="true"/>, a user may speak in a voice channel. </summary> | |||||
/// <summary> If <c>true</c>, a user may speak in a voice channel. </summary> | |||||
public bool Speak => Permissions.GetValue(RawValue, ChannelPermission.Speak); | public bool Speak => Permissions.GetValue(RawValue, ChannelPermission.Speak); | ||||
/// <summary> If <see langword="true"/>, a user may mute users. </summary> | |||||
/// <summary> If <c>true</c>, a user may mute users. </summary> | |||||
public bool MuteMembers => Permissions.GetValue(RawValue, ChannelPermission.MuteMembers); | public bool MuteMembers => Permissions.GetValue(RawValue, ChannelPermission.MuteMembers); | ||||
/// <summary> If <see langword="true"/>, a user may deafen users. </summary> | |||||
/// <summary> If <c>true</c>, a user may deafen users. </summary> | |||||
public bool DeafenMembers => Permissions.GetValue(RawValue, ChannelPermission.DeafenMembers); | public bool DeafenMembers => Permissions.GetValue(RawValue, ChannelPermission.DeafenMembers); | ||||
/// <summary> If <see langword="true"/>, a user may move other users between voice channels. </summary> | |||||
/// <summary> If <c>true</c>, a user may move other users between voice channels. </summary> | |||||
public bool MoveMembers => Permissions.GetValue(RawValue, ChannelPermission.MoveMembers); | public bool MoveMembers => Permissions.GetValue(RawValue, ChannelPermission.MoveMembers); | ||||
/// <summary> If <see langword="true"/>, a user may use voice-activity-detection rather than push-to-talk. </summary> | |||||
/// <summary> If <c>true</c>, a user may use voice-activity-detection rather than push-to-talk. </summary> | |||||
public bool UseVAD => Permissions.GetValue(RawValue, ChannelPermission.UseVAD); | public bool UseVAD => Permissions.GetValue(RawValue, ChannelPermission.UseVAD); | ||||
/// <summary> If <see langword="true"/>, 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 implictly grants all other permissions. </summary> | |||||
public bool ManageRoles => Permissions.GetValue(RawValue, ChannelPermission.ManageRoles); | public bool ManageRoles => Permissions.GetValue(RawValue, ChannelPermission.ManageRoles); | ||||
/// <summary> If <see langword="true"/>, 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); | ||||
/// <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> | ||||
@@ -16,65 +16,65 @@ namespace Discord | |||||
/// <summary> Gets a packed value representing all the permissions in this <see cref="GuildPermissions"/>. </summary> | /// <summary> Gets a packed value representing all the permissions in this <see cref="GuildPermissions"/>. </summary> | ||||
public ulong RawValue { get; } | public ulong RawValue { get; } | ||||
/// <summary> If <see langword="true"/>, a user may create invites. </summary> | |||||
/// <summary> If <c>true</c>, a user may create invites. </summary> | |||||
public bool CreateInstantInvite => Permissions.GetValue(RawValue, GuildPermission.CreateInstantInvite); | public bool CreateInstantInvite => Permissions.GetValue(RawValue, GuildPermission.CreateInstantInvite); | ||||
/// <summary> If <see langword="true"/>, a user may ban users from the guild. </summary> | |||||
/// <summary> If <c>true</c>, a user may ban users from the guild. </summary> | |||||
public bool BanMembers => Permissions.GetValue(RawValue, GuildPermission.BanMembers); | public bool BanMembers => Permissions.GetValue(RawValue, GuildPermission.BanMembers); | ||||
/// <summary> If <see langword="true"/>, a user may kick users from the guild. </summary> | |||||
/// <summary> If <c>true</c>, a user may kick users from the guild. </summary> | |||||
public bool KickMembers => Permissions.GetValue(RawValue, GuildPermission.KickMembers); | public bool KickMembers => Permissions.GetValue(RawValue, GuildPermission.KickMembers); | ||||
/// <summary> If <see langword="true"/>, a user is granted all permissions, and cannot have them revoked via channel permissions. </summary> | |||||
/// <summary> If <c>true</c>, a user is granted all permissions, and cannot have them revoked via channel permissions. </summary> | |||||
public bool Administrator => Permissions.GetValue(RawValue, GuildPermission.Administrator); | public bool Administrator => Permissions.GetValue(RawValue, GuildPermission.Administrator); | ||||
/// <summary> If <see langword="true"/>, a user may create, delete and modify channels. </summary> | |||||
/// <summary> If <c>true</c>, a user may create, delete and modify channels. </summary> | |||||
public bool ManageChannels => Permissions.GetValue(RawValue, GuildPermission.ManageChannels); | public bool ManageChannels => Permissions.GetValue(RawValue, GuildPermission.ManageChannels); | ||||
/// <summary> If <see langword="true"/>, a user may adjust guild properties. </summary> | |||||
/// <summary> If <c>true</c>, a user may adjust guild properties. </summary> | |||||
public bool ManageGuild => Permissions.GetValue(RawValue, GuildPermission.ManageGuild); | public bool ManageGuild => Permissions.GetValue(RawValue, GuildPermission.ManageGuild); | ||||
/// <summary> If <see langword="true"/>, a user may add reactions. </summary> | |||||
/// <summary> If <c>true</c>, a user may add reactions. </summary> | |||||
public bool AddReactions => Permissions.GetValue(RawValue, GuildPermission.AddReactions); | public bool AddReactions => Permissions.GetValue(RawValue, GuildPermission.AddReactions); | ||||
/// <summary> If <see langword="true"/>, a user may view the audit log. </summary> | |||||
/// <summary> If <c>true</c>, a user may view the audit log. </summary> | |||||
public bool ViewAuditLog => Permissions.GetValue(RawValue, GuildPermission.ViewAuditLog); | public bool ViewAuditLog => Permissions.GetValue(RawValue, GuildPermission.ViewAuditLog); | ||||
/// <summary> If <see langword="true"/>, a user may join channels. </summary> | |||||
/// <summary> If <c>true</c>, a user may join channels. </summary> | |||||
public bool ReadMessages => Permissions.GetValue(RawValue, GuildPermission.ReadMessages); | public bool ReadMessages => Permissions.GetValue(RawValue, GuildPermission.ReadMessages); | ||||
/// <summary> If <see langword="true"/>, a user may send messages. </summary> | |||||
/// <summary> If <c>true</c>, a user may send messages. </summary> | |||||
public bool SendMessages => Permissions.GetValue(RawValue, GuildPermission.SendMessages); | public bool SendMessages => Permissions.GetValue(RawValue, GuildPermission.SendMessages); | ||||
/// <summary> If <see langword="true"/>, a user may send text-to-speech messages. </summary> | |||||
/// <summary> If <c>true</c>, a user may send text-to-speech messages. </summary> | |||||
public bool SendTTSMessages => Permissions.GetValue(RawValue, GuildPermission.SendTTSMessages); | public bool SendTTSMessages => Permissions.GetValue(RawValue, GuildPermission.SendTTSMessages); | ||||
/// <summary> If <see langword="true"/>, a user may delete messages. </summary> | |||||
/// <summary> If <c>true</c>, a user may delete messages. </summary> | |||||
public bool ManageMessages => Permissions.GetValue(RawValue, GuildPermission.ManageMessages); | public bool ManageMessages => Permissions.GetValue(RawValue, GuildPermission.ManageMessages); | ||||
/// <summary> If <see langword="true"/>, Discord will auto-embed links sent by this user. </summary> | |||||
/// <summary> If <c>true</c>, Discord will auto-embed links sent by this user. </summary> | |||||
public bool EmbedLinks => Permissions.GetValue(RawValue, GuildPermission.EmbedLinks); | public bool EmbedLinks => Permissions.GetValue(RawValue, GuildPermission.EmbedLinks); | ||||
/// <summary> If <see langword="true"/>, a user may send files. </summary> | |||||
/// <summary> If <c>true</c>, a user may send files. </summary> | |||||
public bool AttachFiles => Permissions.GetValue(RawValue, GuildPermission.AttachFiles); | public bool AttachFiles => Permissions.GetValue(RawValue, GuildPermission.AttachFiles); | ||||
/// <summary> If <see langword="true"/>, a user may read previous messages. </summary> | |||||
/// <summary> If <c>true</c>, a user may read previous messages. </summary> | |||||
public bool ReadMessageHistory => Permissions.GetValue(RawValue, GuildPermission.ReadMessageHistory); | public bool ReadMessageHistory => Permissions.GetValue(RawValue, GuildPermission.ReadMessageHistory); | ||||
/// <summary> If <see langword="true"/>, a user may mention @everyone. </summary> | |||||
/// <summary> If <c>true</c>, a user may mention @everyone. </summary> | |||||
public bool MentionEveryone => Permissions.GetValue(RawValue, GuildPermission.MentionEveryone); | public bool MentionEveryone => Permissions.GetValue(RawValue, GuildPermission.MentionEveryone); | ||||
/// <summary> If <see langword="true"/>, a user may use custom emoji from other guilds. </summary> | |||||
/// <summary> If <c>true</c>, a user may use custom emoji from other guilds. </summary> | |||||
public bool UseExternalEmojis => Permissions.GetValue(RawValue, GuildPermission.UseExternalEmojis); | public bool UseExternalEmojis => Permissions.GetValue(RawValue, GuildPermission.UseExternalEmojis); | ||||
/// <summary> If <see langword="true"/>, a user may connect to a voice channel. </summary> | |||||
/// <summary> If <c>true</c>, a user may connect to a voice channel. </summary> | |||||
public bool Connect => Permissions.GetValue(RawValue, GuildPermission.Connect); | public bool Connect => Permissions.GetValue(RawValue, GuildPermission.Connect); | ||||
/// <summary> If <see langword="true"/>, a user may speak in a voice channel. </summary> | |||||
/// <summary> If <c>true</c>, a user may speak in a voice channel. </summary> | |||||
public bool Speak => Permissions.GetValue(RawValue, GuildPermission.Speak); | public bool Speak => Permissions.GetValue(RawValue, GuildPermission.Speak); | ||||
/// <summary> If <see langword="true"/>, a user may mute users. </summary> | |||||
/// <summary> If <c>true</c>, a user may mute users. </summary> | |||||
public bool MuteMembers => Permissions.GetValue(RawValue, GuildPermission.MuteMembers); | public bool MuteMembers => Permissions.GetValue(RawValue, GuildPermission.MuteMembers); | ||||
/// <summary> If <see langword="true"/>, a user may deafen users. </summary> | |||||
/// <summary> If <c>true</c>, a user may deafen users. </summary> | |||||
public bool DeafenMembers => Permissions.GetValue(RawValue, GuildPermission.DeafenMembers); | public bool DeafenMembers => Permissions.GetValue(RawValue, GuildPermission.DeafenMembers); | ||||
/// <summary> If <see langword="true"/>, a user may move other users between voice channels. </summary> | |||||
/// <summary> If <c>true</c>, a user may move other users between voice channels. </summary> | |||||
public bool MoveMembers => Permissions.GetValue(RawValue, GuildPermission.MoveMembers); | public bool MoveMembers => Permissions.GetValue(RawValue, GuildPermission.MoveMembers); | ||||
/// <summary> If <see langword="true"/>, a user may use voice-activity-detection rather than push-to-talk. </summary> | |||||
/// <summary> If <c>true</c>, a user may use voice-activity-detection rather than push-to-talk. </summary> | |||||
public bool UseVAD => Permissions.GetValue(RawValue, GuildPermission.UseVAD); | public bool UseVAD => Permissions.GetValue(RawValue, GuildPermission.UseVAD); | ||||
/// <summary> If <see langword="true"/>, a user may change their own nickname. </summary> | |||||
/// <summary> If <c>true</c>, a user may change their own nickname. </summary> | |||||
public bool ChangeNickname => Permissions.GetValue(RawValue, GuildPermission.ChangeNickname); | public bool ChangeNickname => Permissions.GetValue(RawValue, GuildPermission.ChangeNickname); | ||||
/// <summary> If <see langword="true"/>, a user may change the nickname of other users. </summary> | |||||
/// <summary> If <c>true</c>, a user may change the nickname of other users. </summary> | |||||
public bool ManageNicknames => Permissions.GetValue(RawValue, GuildPermission.ManageNicknames); | public bool ManageNicknames => Permissions.GetValue(RawValue, GuildPermission.ManageNicknames); | ||||
/// <summary> If <see langword="true"/>, a user may adjust roles. </summary> | |||||
/// <summary> If <c>true</c>, a user may adjust roles. </summary> | |||||
public bool ManageRoles => Permissions.GetValue(RawValue, GuildPermission.ManageRoles); | public bool ManageRoles => Permissions.GetValue(RawValue, GuildPermission.ManageRoles); | ||||
/// <summary> If <see langword="true"/>, a user may edit the webhooks for this guild. </summary> | |||||
/// <summary> If <c>true</c>, a user may edit the webhooks for this guild. </summary> | |||||
public bool ManageWebhooks => Permissions.GetValue(RawValue, GuildPermission.ManageWebhooks); | public bool ManageWebhooks => Permissions.GetValue(RawValue, GuildPermission.ManageWebhooks); | ||||
/// <summary> If <see langword="true"/>, a user may edit the emojis for this guild. </summary> | |||||
/// <summary> If <c>true</c>, a user may edit the emojis for this guild. </summary> | |||||
public bool ManageEmojis => Permissions.GetValue(RawValue, GuildPermission.ManageEmojis); | public bool ManageEmojis => Permissions.GetValue(RawValue, GuildPermission.ManageEmojis); | ||||
/// <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> | ||||
@@ -4,7 +4,7 @@ using System.Diagnostics; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Represents a Discord color. | |||||
/// Represents a color used in Discord. | |||||
/// </summary> | /// </summary> | ||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public struct Color | public struct Color | ||||
@@ -65,7 +65,7 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Initializes a <see cref="Color" /> struct with the given raw value. | /// Initializes a <see cref="Color" /> struct with the given raw value. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="rawValue">A raw value for the color (e.g. <c>0x607D8B</c>).</param> | |||||
/// <param name="rawValue">The raw value of the color (e.g. <c>0x607D8B</c>).</param> | |||||
public Color(uint rawValue) | public Color(uint rawValue) | ||||
{ | { | ||||
RawValue = rawValue; | RawValue = rawValue; | ||||
@@ -73,9 +73,9 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Initializes a <see cref="Color" /> struct with the given RGB bytes. | /// Initializes a <see cref="Color" /> struct with the given RGB bytes. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="r">The <see langword="byte"/> that represents the red color.</param> | |||||
/// <param name="g">The <see langword="byte"/> that represents the green color.</param> | |||||
/// <param name="b">The <see langword="byte"/> that represents the blue color.</param> | |||||
/// <param name="r">The byte that represents the red color.</param> | |||||
/// <param name="g">The byte that represents the green color.</param> | |||||
/// <param name="b">The byte that represents the blue color.</param> | |||||
public Color(byte r, byte g, byte b) | public Color(byte r, byte g, byte b) | ||||
{ | { | ||||
RawValue = | RawValue = | ||||
@@ -126,8 +126,11 @@ namespace Discord | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the hexadecimal representation of the color (e.g. #000ccc). | |||||
/// Gets the hexadecimal representation of the color (e.g. <c>#000ccc</c>). | |||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A hexadecimal string of the color. | |||||
/// </returns> | |||||
public override string ToString() => | public override string ToString() => | ||||
$"#{Convert.ToString(RawValue, 16)}"; | $"#{Convert.ToString(RawValue, 16)}"; | ||||
private string DebuggerDisplay => | private string DebuggerDisplay => | ||||
@@ -21,24 +21,24 @@ namespace Discord | |||||
/// Determines whether the role can be separated in the user list. | /// Determines whether the role can be separated in the user list. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
/// Returns <see langword="true"/> if users of this role are separated in the user list; otherwise, returns | |||||
/// <see langword="false"/>. | |||||
/// Returns <c>true</c> if users of this role are separated in the user list; otherwise, returns | |||||
/// <c>false</c>. | |||||
/// </returns> | /// </returns> | ||||
bool IsHoisted { get; } | bool IsHoisted { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Determines whether the role is managed by Discord. | /// Determines whether the role is managed by Discord. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
/// Returns <see langword="true"/> if this role is automatically managed by Discord; otherwise, returns | |||||
/// <see langword="false"/>. | |||||
/// Returns <c>true</c> if this role is automatically managed by Discord; otherwise, returns | |||||
/// <c>false</c>. | |||||
/// </returns> | /// </returns> | ||||
bool IsManaged { get; } | bool IsManaged { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Determines whether the role is mentionable. | /// Determines whether the role is mentionable. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | /// <returns> | ||||
/// Returns <see langword="true"/> if this role may be mentioned in messages; otherwise, returns | |||||
/// <see langword="false"/>. | |||||
/// Returns <c>true</c> if this role may be mentioned in messages; otherwise, returns | |||||
/// <c>false</c>. | |||||
/// </returns> | /// </returns> | ||||
bool IsMentionable { get; } | bool IsMentionable { get; } | ||||
/// <summary> | /// <summary> | ||||
@@ -3,16 +3,7 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Properties that are used to modify an <see cref="IRole" /> with the specified changes. | /// Properties that are used to modify an <see cref="IRole" /> with the specified changes. | ||||
/// </summary> | /// </summary> | ||||
/// <example> | |||||
/// <code lang="c#"> | |||||
/// await role.ModifyAsync(x => | |||||
/// { | |||||
/// x.Color = new Color(180, 15, 40); | |||||
/// x.Hoist = true; | |||||
/// }); | |||||
/// </code> | |||||
/// </example> | |||||
/// <seealso cref="T:Discord.IRole" /> | |||||
/// <seealso cref="IRole.ModifyAsync" /> | |||||
public class RoleProperties | public class RoleProperties | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
@@ -5,36 +5,28 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Properties that are used to modify an <see cref="IGuildUser" /> with the following parameters. | /// Properties that are used to modify an <see cref="IGuildUser" /> with the following parameters. | ||||
/// </summary> | /// </summary> | ||||
/// <example> | |||||
/// <code lang="c#"> | |||||
/// await guildUser.ModifyAsync(x => | |||||
/// { | |||||
/// x.Nickname = $"festive {guildUser.Username}"; | |||||
/// }); | |||||
/// </code> | |||||
/// </example> | |||||
/// <seealso cref="T:Discord.IGuildUser" /> | |||||
/// <seealso cref="IGuildUser.ModifyAsync" /> | |||||
public class GuildUserProperties | public class GuildUserProperties | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Gets or sets whether the user should be muted in a voice channel. | /// Gets or sets whether the user should be muted in a voice channel. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks> | /// <remarks> | ||||
/// If this value is set to <see langword="true"/>, no user will be able to hear this user speak in the guild. | |||||
/// If this value is set to <c>true</c>, no user will be able to hear this user speak in the guild. | |||||
/// </remarks> | /// </remarks> | ||||
public Optional<bool> Mute { get; set; } | public Optional<bool> Mute { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets or sets whether the user should be deafened in a voice channel. | /// Gets or sets whether the user should be deafened in a voice channel. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks> | /// <remarks> | ||||
/// If this value is set to <see langword="true"/>, this user will not be able to hear anyone speak in the guild. | |||||
/// If this value is set to <c>true</c>, this user will not be able to hear anyone speak in the guild. | |||||
/// </remarks> | /// </remarks> | ||||
public Optional<bool> Deaf { get; set; } | public Optional<bool> Deaf { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets or sets the user's nickname. | /// Gets or sets the user's nickname. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks> | /// <remarks> | ||||
/// To clear the user's nickname, this value can be set to <see langword="null" /> or | |||||
/// To clear the user's nickname, this value can be set to <c>null</c> or | |||||
/// <see cref="string.Empty" />. | /// <see cref="string.Empty" />. | ||||
/// </remarks> | /// </remarks> | ||||
public Optional<string> Nickname { get; set; } | public Optional<string> Nickname { get; set; } | ||||
@@ -13,11 +13,11 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
string Email { get; } | string Email { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if this user's email has been verified. | |||||
/// Returns <c>true</c> if this user's email has been verified. | |||||
/// </summary> | /// </summary> | ||||
bool IsVerified { get; } | bool IsVerified { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if this user has enabled MFA on their account. | |||||
/// Returns <c>true</c> if this user has enabled MFA on their account. | |||||
/// </summary> | /// </summary> | ||||
bool IsMfaEnabled { get; } | bool IsMfaEnabled { get; } | ||||
@@ -12,11 +12,18 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
string AvatarId { get; } | string AvatarId { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the URL to this user's avatar. | |||||
/// </summary> | |||||
/// Returns a URL to this user's avatar. | |||||
/// </summary> | |||||
/// <param name="format">The format to return.</param> | |||||
/// <param name="size"> | |||||
/// The size of the image to return in. This can be any power of two between 16 and 2048. | |||||
/// </param> | |||||
/// <returns> | |||||
/// User's avatar URL. | |||||
/// </returns> | |||||
string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128); | string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128); | ||||
/// <summary> | /// <summary> | ||||
/// Gets the URL to this user's default avatar. | |||||
/// Returns the URL to this user's default avatar. | |||||
/// </summary> | /// </summary> | ||||
string GetDefaultAvatarUrl(); | string GetDefaultAvatarUrl(); | ||||
/// <summary> | /// <summary> | ||||
@@ -28,11 +35,11 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
ushort DiscriminatorValue { get; } | ushort DiscriminatorValue { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if this user is a bot user. | |||||
/// Gets <c>true</c> if this user is a bot user. | |||||
/// </summary> | /// </summary> | ||||
bool IsBot { get; } | bool IsBot { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true"/> if this user is a webhook user. | |||||
/// Gets <c>true</c> if this user is a webhook user. | |||||
/// </summary> | /// </summary> | ||||
bool IsWebhook { get; } | bool IsWebhook { get; } | ||||
/// <summary> | /// <summary> | ||||
@@ -43,6 +50,10 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Returns a direct message channel to this user, or create one if it does not already exist. | /// Returns a direct message channel to this user, or create one if it does not already exist. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// An awaitable Task containing the DM channel. | |||||
/// </returns> | |||||
Task<IDMChannel> GetOrCreateDMChannelAsync(RequestOptions options = null); | Task<IDMChannel> GetOrCreateDMChannelAsync(RequestOptions options = null); | ||||
} | } | ||||
} | } |
@@ -6,27 +6,27 @@ namespace Discord | |||||
public interface IVoiceState | public interface IVoiceState | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true" /> if the guild has deafened this user. | |||||
/// Returns <c>true</c> if the guild has deafened this user. | |||||
/// </summary> | /// </summary> | ||||
bool IsDeafened { get; } | bool IsDeafened { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true" /> if the guild has muted this user. | |||||
/// Returns <c>true</c> if the guild has muted this user. | |||||
/// </summary> | /// </summary> | ||||
bool IsMuted { get; } | bool IsMuted { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true" /> if this user has marked themselves as deafened. | |||||
/// Returns <c>true</c> if this user has marked themselves as deafened. | |||||
/// </summary> | /// </summary> | ||||
bool IsSelfDeafened { get; } | bool IsSelfDeafened { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true" /> if this user has marked themselves as muted. | |||||
/// Returns <c>true</c> if this user has marked themselves as muted. | |||||
/// </summary> | /// </summary> | ||||
bool IsSelfMuted { get; } | bool IsSelfMuted { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Returns <see langword="true" /> if the guild is temporarily blocking audio to/from this user. | |||||
/// Returns <c>true</c> if the guild is temporarily blocking audio to/from this user. | |||||
/// </summary> | /// </summary> | ||||
bool IsSuppressed { get; } | bool IsSuppressed { get; } | ||||
/// <summary> | /// <summary> | ||||
/// Gets the voice channel this user is currently in, or <see langword="null"/> if none. | |||||
/// Gets the voice channel this user is currently in, or <c>null</c> if none. | |||||
/// </summary> | /// </summary> | ||||
IVoiceChannel VoiceChannel { get; } | IVoiceChannel VoiceChannel { get; } | ||||
/// <summary> | /// <summary> | ||||
@@ -3,15 +3,7 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Properties that are used to modify the <see cref="ISelfUser" /> with the specified changes. | /// Properties that are used to modify the <see cref="ISelfUser" /> with the specified changes. | ||||
/// </summary> | /// </summary> | ||||
/// <example> | |||||
/// <code lang="c#"> | |||||
/// await Context.Client.CurrentUser.ModifyAsync(x => | |||||
/// { | |||||
/// x.Avatar = new Image(File.OpenRead("avatar.jpg")); | |||||
/// }); | |||||
/// </code> | |||||
/// </example> | |||||
/// <seealso cref="T:Discord.ISelfUser" /> | |||||
/// <seealso cref="ISelfUser.ModifyAsync" /> | |||||
public class SelfUserProperties | public class SelfUserProperties | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
@@ -3,16 +3,7 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Properties used to modify an <see cref="IWebhook" /> with the specified changes. | /// Properties used to modify an <see cref="IWebhook" /> with the specified changes. | ||||
/// </summary> | /// </summary> | ||||
/// <example> | |||||
/// <code lang="c#"> | |||||
/// await webhook.ModifyAsync(x => | |||||
/// { | |||||
/// x.Name = "Bob"; | |||||
/// x.Avatar = new Image("avatar.jpg"); | |||||
/// }); | |||||
/// </code> | |||||
/// </example> | |||||
/// <seealso cref="T:Discord.IWebhook" /> | |||||
/// <seealso cref="IWebhook.ModifyAsync"/> | |||||
public class WebhookProperties | public class WebhookProperties | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
@@ -0,0 +1,14 @@ | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Represents the type of a webhook. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// This type is currently unused, and is only returned in audit log responses. | |||||
/// </remarks> | |||||
public enum WebhookType | |||||
{ | |||||
/// <summary> An incoming webhook </summary> | |||||
Incoming = 1 | |||||
} | |||||
} |
@@ -1,3 +1,4 @@ | |||||
using System; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using System.IO; | using System.IO; | ||||
@@ -6,7 +7,16 @@ namespace Discord | |||||
/// <summary> An extension class for various Discord user objects. </summary> | /// <summary> An extension class for various Discord user objects. </summary> | ||||
public static class UserExtensions | public static class UserExtensions | ||||
{ | { | ||||
/// <summary> Sends a message to the user via DM. </summary> | |||||
/// <summary> | |||||
/// Sends a message via DM. | |||||
/// </summary> | |||||
/// <param name="text">The message to be sent.</param> | |||||
/// <param name="isTTS">Whether the message should be read aloud by Discord or not.</param> | |||||
/// <param name="embed">The <see cref="EmbedType.Rich"/> <see cref="Embed"/> to be sent.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// An awaitable Task containing the message sent to the channel. | |||||
/// </returns> | |||||
public static async Task<IUserMessage> SendMessageAsync(this IUser user, | public static async Task<IUserMessage> SendMessageAsync(this IUser user, | ||||
string text, | string text, | ||||
bool isTTS = false, | bool isTTS = false, | ||||
@@ -16,7 +26,23 @@ namespace Discord | |||||
return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync(text, isTTS, embed, options).ConfigureAwait(false); | return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync(text, isTTS, embed, options).ConfigureAwait(false); | ||||
} | } | ||||
/// <summary> Sends a file to the user via DM. </summary> | |||||
/// <summary> | |||||
/// Sends a file to this message channel with an optional caption. | |||||
/// </summary> | |||||
/// <param name="stream">The <see cref="Stream"/> of the file to be sent.</param> | |||||
/// <param name="filename">The name of the attachment.</param> | |||||
/// <param name="text">The message to be sent.</param> | |||||
/// <param name="isTTS">Whether the message should be read aloud by Discord or not.</param> | |||||
/// <param name="embed">The <see cref="EmbedType.Rich"/> <see cref="Embed"/> to be sent.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <remarks> | |||||
/// If you wish to upload an image and have it embedded in a <see cref="EmbedType.Rich"/> embed, you may | |||||
/// upload the file and refer to the file with "attachment://filename.ext" in the | |||||
/// <see cref="Discord.EmbedBuilder.ImageUrl"/>. | |||||
/// </remarks> | |||||
/// <returns> | |||||
/// An awaitable Task containing the message sent to the channel. | |||||
/// </returns> | |||||
public static async Task<IUserMessage> SendFileAsync(this IUser user, | public static async Task<IUserMessage> SendFileAsync(this IUser user, | ||||
Stream stream, | Stream stream, | ||||
string filename, | string filename, | ||||
@@ -30,7 +56,22 @@ namespace Discord | |||||
} | } | ||||
#if FILESYSTEM | #if FILESYSTEM | ||||
/// <summary> Sends a file to the user via DM. </summary> | |||||
/// <summary> | |||||
/// Sends a file via DM with an optional caption. | |||||
/// </summary> | |||||
/// <param name="filePath">The file path of the file.</param> | |||||
/// <param name="text">The message to be sent.</param> | |||||
/// <param name="isTTS">Whether the message should be read aloud by Discord or not.</param> | |||||
/// <param name="embed">The <see cref="EmbedType.Rich"/> <see cref="Embed"/> to be sent.</param> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <remarks> | |||||
/// If you wish to upload an image and have it embedded in a <see cref="EmbedType.Rich"/> embed, you may | |||||
/// upload the file and refer to the file with "attachment://filename.ext" in the | |||||
/// <see cref="Discord.EmbedBuilder.ImageUrl"/>. | |||||
/// </remarks> | |||||
/// <returns> | |||||
/// An awaitable Task containing the message sent to the channel. | |||||
/// </returns> | |||||
public static async Task<IUserMessage> SendFileAsync(this IUser user, | public static async Task<IUserMessage> SendFileAsync(this IUser user, | ||||
string filePath, | string filePath, | ||||
string text = null, | string text = null, | ||||
@@ -41,10 +82,15 @@ namespace Discord | |||||
return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false); | return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false); | ||||
} | } | ||||
#endif | #endif | ||||
/// <summary> Bans the provided user from the guild and optionally prunes their recent messages. </summary> | |||||
/// <param name="user"> The user to ban. </param> | |||||
/// <param name="pruneDays"> The number of days to remove messages from this user for - must be between [0, 7]</param> | |||||
/// <param name="reason"> The reason of the ban to be written in the audit log. </param> | |||||
/// <summary> | |||||
/// Bans the provided user from the guild and optionally prunes their recent messages. | |||||
/// </summary> | |||||
/// <param name="user">The user to ban.</param> | |||||
/// <param name="pruneDays"> | |||||
/// The number of days to remove messages from this user for - must be between [0, 7] | |||||
/// </param> | |||||
/// <param name="reason">The reason of the ban to be written in the audit log.</param> | |||||
/// <exception cref="ArgumentException"><paramref name="pruneDays" /> is not between 0 to 7.</exception> | |||||
public static Task BanAsync(this IGuildUser user, int pruneDays = 0, string reason = null, RequestOptions options = null) | public static Task BanAsync(this IGuildUser user, int pruneDays = 0, string reason = null, RequestOptions options = null) | ||||
=> user.Guild.AddBanAsync(user, pruneDays, reason, options); | => user.Guild.AddBanAsync(user, pruneDays, reason, options); | ||||
} | } | ||||
@@ -10,16 +10,33 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
public interface IDiscordClient : IDisposable | public interface IDiscordClient : IDisposable | ||||
{ | { | ||||
/// <summary> | |||||
/// Gets the current state of connection. | |||||
/// </summary> | |||||
ConnectionState ConnectionState { get; } | ConnectionState ConnectionState { get; } | ||||
/// <summary> | |||||
/// Gets the currently logged-in user. | |||||
/// </summary> | |||||
ISelfUser CurrentUser { get; } | ISelfUser CurrentUser { get; } | ||||
/// <summary> | |||||
/// Gets the token type of the logged-in user. | |||||
/// </summary> | |||||
TokenType TokenType { get; } | TokenType TokenType { get; } | ||||
Task StartAsync(); | Task StartAsync(); | ||||
Task StopAsync(); | Task StopAsync(); | ||||
/// <summary> | /// <summary> | ||||
/// Gets the application information associated with this account. | |||||
/// Gets a Discord application information for the logged-in user. | |||||
/// </summary> | /// </summary> | ||||
/// <remarks> | |||||
/// This method reflects your application information you submitted when creating a Discord application via | |||||
/// the Developer Portal. | |||||
/// </remarks> | |||||
/// <param name="options">The options to be used when sending the request.</param> | |||||
/// <returns> | |||||
/// An awaitable <see cref="Task"/> containing the application information. | |||||
/// </returns> | |||||
Task<IApplication> GetApplicationInfoAsync(RequestOptions options = null); | Task<IApplication> GetApplicationInfoAsync(RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
@@ -36,11 +53,21 @@ namespace Discord | |||||
/// </param> | /// </param> | ||||
Task<IReadOnlyCollection<IPrivateChannel>> GetPrivateChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IReadOnlyCollection<IPrivateChannel>> GetPrivateChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Gets a list of direct message channels. | |||||
/// Returns a collection of direct message channels. | |||||
/// </summary> | /// </summary> | ||||
/// <remarks> | |||||
/// This method returns a collection of currently opened direct message channels. | |||||
/// <note type="note"> | |||||
/// This method will not return previously opened DM channels outside of the current session! If you | |||||
/// have just started the client, this may return an empty collection. | |||||
/// </note> | |||||
/// </remarks> | |||||
/// <param name="mode"> | /// <param name="mode"> | ||||
/// The <see cref="CacheMode" /> that determines whether the object should be fetched from cache. | /// The <see cref="CacheMode" /> that determines whether the object should be fetched from cache. | ||||
/// </param> | /// </param> | ||||
/// <returns> | |||||
/// An awaitable <see cref="Task" /> containing a collection of DM channels. | |||||
/// </returns> | |||||
Task<IReadOnlyCollection<IDMChannel>> GetDMChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IReadOnlyCollection<IDMChannel>> GetDMChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
/// <summary> | /// <summary> | ||||
/// Gets a list of group channels. | /// Gets a list of group channels. | ||||
@@ -23,7 +23,7 @@ namespace Discord.Net | |||||
/// <returns> | /// <returns> | ||||
/// A | /// A | ||||
/// <see href="https://discordapp.com/developers/docs/topics/opcodes-and-status-codes#json">JSON error code</see> | /// <see href="https://discordapp.com/developers/docs/topics/opcodes-and-status-codes#json">JSON error code</see> | ||||
/// from Discord, or <see langword="null"/> if none. | |||||
/// from Discord, or <c>null</c> if none. | |||||
/// </returns> | /// </returns> | ||||
public int? DiscordCode { get; } | public int? DiscordCode { get; } | ||||
/// <summary> | /// <summary> | ||||
@@ -14,7 +14,7 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Gets or set the max time, in milliseconds, to wait for this request to complete. If | /// Gets or set the max time, in milliseconds, to wait for this request to complete. If | ||||
/// <see langword="null"/>, a request will not time out. If a rate limit has been triggered for this | |||||
/// <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. | /// request's bucket and will not be unpaused in time, this request will fail immediately. | ||||
/// </summary> | /// </summary> | ||||
public int? Timeout { get; set; } | public int? Timeout { get; set; } | ||||
@@ -25,7 +25,7 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
/// <remarks> | /// <remarks> | ||||
/// This value is not guaranteed to be set; in cases where the entity cannot be pulled from cache, it is | /// This value is not guaranteed to be set; in cases where the entity cannot be pulled from cache, it is | ||||
/// <see langword="null"/>. | |||||
/// <c>null</c>. | |||||
/// </remarks> | /// </remarks> | ||||
public TEntity Value { get; } | public TEntity Value { get; } | ||||
private Func<Task<TEntity>> DownloadFunc { get; } | private Func<Task<TEntity>> DownloadFunc { get; } | ||||
@@ -157,7 +157,7 @@ namespace Discord | |||||
: this(collection, EqualityComparer<T>.Default) { } | : this(collection, EqualityComparer<T>.Default) { } | ||||
public ConcurrentHashSet(IEqualityComparer<T> comparer) | public ConcurrentHashSet(IEqualityComparer<T> comparer) | ||||
: this(DefaultConcurrencyLevel, DefaultCapacity, true, comparer) { } | : this(DefaultConcurrencyLevel, DefaultCapacity, true, comparer) { } | ||||
/// <exception cref="ArgumentNullException"><paramref name="collection"/> is <see langword="null"/></exception> | |||||
/// <exception cref="ArgumentNullException"><paramref name="collection"/> is <c>null</c></exception> | |||||
public ConcurrentHashSet(IEnumerable<T> collection, IEqualityComparer<T> comparer) | public ConcurrentHashSet(IEnumerable<T> collection, IEqualityComparer<T> comparer) | ||||
: this(comparer) | : this(comparer) | ||||
{ | { | ||||
@@ -165,7 +165,7 @@ namespace Discord | |||||
InitializeFromCollection(collection); | InitializeFromCollection(collection); | ||||
} | } | ||||
/// <exception cref="ArgumentNullException"> | /// <exception cref="ArgumentNullException"> | ||||
/// <paramref name="collection" /> or <paramref name="comparer" /> is <see langword="null" /> | |||||
/// <paramref name="collection" /> or <paramref name="comparer" /> is <c>null</c> | |||||
/// </exception> | /// </exception> | ||||
public ConcurrentHashSet(int concurrencyLevel, IEnumerable<T> collection, IEqualityComparer<T> comparer) | public ConcurrentHashSet(int concurrencyLevel, IEnumerable<T> collection, IEqualityComparer<T> comparer) | ||||
: this(concurrencyLevel, DefaultCapacity, false, comparer) | : this(concurrencyLevel, DefaultCapacity, false, comparer) | ||||
@@ -210,7 +210,7 @@ namespace Discord | |||||
if (_budget == 0) | if (_budget == 0) | ||||
_budget = _tables._buckets.Length / _tables._locks.Length; | _budget = _tables._buckets.Length / _tables._locks.Length; | ||||
} | } | ||||
/// <exception cref="ArgumentNullException"><paramref name="value"/> is <see langword="null"/></exception> | |||||
/// <exception cref="ArgumentNullException"><paramref name="value"/> is <c>null</c></exception> | |||||
public bool ContainsKey(T value) | public bool ContainsKey(T value) | ||||
{ | { | ||||
if (value == null) throw new ArgumentNullException(nameof(value)); | if (value == null) throw new ArgumentNullException(nameof(value)); | ||||
@@ -234,7 +234,7 @@ namespace Discord | |||||
return false; | return false; | ||||
} | } | ||||
/// <exception cref="ArgumentNullException"><paramref name="value"/> is <see langword="null"/></exception> | |||||
/// <exception cref="ArgumentNullException"><paramref name="value"/> is <c>null</c></exception> | |||||
public bool TryAdd(T value) | public bool TryAdd(T value) | ||||
{ | { | ||||
if (value == null) throw new ArgumentNullException(nameof(value)); | if (value == null) throw new ArgumentNullException(nameof(value)); | ||||
@@ -284,7 +284,7 @@ namespace Discord | |||||
} | } | ||||
} | } | ||||
/// <exception cref="ArgumentNullException"><paramref name="value"/> is <see langword="null"/></exception> | |||||
/// <exception cref="ArgumentNullException"><paramref name="value"/> is <c>null</c></exception> | |||||
public bool TryRemove(T value) | public bool TryRemove(T value) | ||||
{ | { | ||||
if (value == null) throw new ArgumentNullException(nameof(value)); | if (value == null) throw new ArgumentNullException(nameof(value)); | ||||
@@ -16,16 +16,25 @@ namespace Discord | |||||
/// <summary> | /// <summary> | ||||
/// Returns a mention string based on the user ID. | /// Returns a mention string based on the user ID. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A user mention string (e.g. <@80351110224678912>). | |||||
/// </returns> | |||||
public static string MentionUser(ulong id) => MentionUser(id.ToString(), true); | public static string MentionUser(ulong id) => MentionUser(id.ToString(), true); | ||||
internal static string MentionChannel(string id) => $"<#{id}>"; | internal static string MentionChannel(string id) => $"<#{id}>"; | ||||
/// <summary> | /// <summary> | ||||
/// Returns a mention string based on the channel ID. | /// Returns a mention string based on the channel ID. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A channel mention string (e.g. <#103735883630395392>). | |||||
/// </returns> | |||||
public static string MentionChannel(ulong id) => MentionChannel(id.ToString()); | public static string MentionChannel(ulong id) => MentionChannel(id.ToString()); | ||||
internal static string MentionRole(string id) => $"<@&{id}>"; | internal static string MentionRole(string id) => $"<@&{id}>"; | ||||
/// <summary> | /// <summary> | ||||
/// Returns a mention string based on the role ID. | /// Returns a mention string based on the role ID. | ||||
/// </summary> | /// </summary> | ||||
/// <returns> | |||||
/// A role mention string (e.g. <@&165511591545143296>). | |||||
/// </returns> | |||||
public static string MentionRole(ulong id) => MentionRole(id.ToString()); | public static string MentionRole(ulong id) => MentionRole(id.ToString()); | ||||
/// <summary> | /// <summary> | ||||
@@ -0,0 +1,16 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API | |||||
{ | |||||
internal class AuditLog | |||||
{ | |||||
[JsonProperty("webhooks")] | |||||
public Webhook[] Webhooks { get; set; } | |||||
[JsonProperty("users")] | |||||
public User[] Users { get; set; } | |||||
[JsonProperty("audit_log_entries")] | |||||
public AuditLogEntry[] Entries { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,17 @@ | |||||
using Newtonsoft.Json; | |||||
using Newtonsoft.Json.Linq; | |||||
namespace Discord.API | |||||
{ | |||||
internal class AuditLogChange | |||||
{ | |||||
[JsonProperty("key")] | |||||
public string ChangedProperty { get; set; } | |||||
[JsonProperty("new_value")] | |||||
public JToken NewValue { get; set; } | |||||
[JsonProperty("old_value")] | |||||
public JToken OldValue { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,26 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API | |||||
{ | |||||
internal class AuditLogEntry | |||||
{ | |||||
[JsonProperty("target_id")] | |||||
public ulong? TargetId { get; set; } | |||||
[JsonProperty("user_id")] | |||||
public ulong UserId { get; set; } | |||||
[JsonProperty("changes")] | |||||
public AuditLogChange[] Changes { get; set; } | |||||
[JsonProperty("options")] | |||||
public AuditLogOptions Options { get; set; } | |||||
[JsonProperty("id")] | |||||
public ulong Id { get; set; } | |||||
[JsonProperty("action_type")] | |||||
public ActionType Action { get; set; } | |||||
[JsonProperty("reason")] | |||||
public string Reason { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,27 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.API | |||||
{ | |||||
internal class AuditLogOptions | |||||
{ | |||||
//Message delete | |||||
[JsonProperty("count")] | |||||
public int? MessageDeleteCount { get; set; } | |||||
[JsonProperty("channel_id")] | |||||
public ulong? MessageDeleteChannelId { get; set; } | |||||
//Prune | |||||
[JsonProperty("delete_member_days")] | |||||
public int? PruneDeleteMemberDays { get; set; } | |||||
[JsonProperty("members_removed")] | |||||
public int? PruneMembersRemoved { get; set; } | |||||
//Overwrite Update | |||||
[JsonProperty("role_name")] | |||||
public string OverwriteRoleName { get; set; } | |||||
[JsonProperty("type")] | |||||
public string OverwriteType { get; set; } | |||||
[JsonProperty("id")] | |||||
public ulong? OverwriteTargetId { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,8 @@ | |||||
namespace Discord.API.Rest | |||||
{ | |||||
class GetAuditLogsParams | |||||
{ | |||||
public Optional<int> Limit { get; set; } | |||||
public Optional<ulong> BeforeEntryId { get; set; } | |||||
} | |||||
} |
@@ -812,6 +812,15 @@ namespace Discord.API | |||||
var ids = new BucketIds(guildId: guildId); | var ids = new BucketIds(guildId: guildId); | ||||
return await SendAsync<IReadOnlyCollection<Ban>>("GET", () => $"guilds/{guildId}/bans", ids, options: options).ConfigureAwait(false); | return await SendAsync<IReadOnlyCollection<Ban>>("GET", () => $"guilds/{guildId}/bans", ids, options: options).ConfigureAwait(false); | ||||
} | } | ||||
public async Task<Ban> GetGuildBanAsync(ulong guildId, ulong userId, RequestOptions options) | |||||
{ | |||||
Preconditions.NotEqual(userId, 0, nameof(userId)); | |||||
Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||||
options = RequestOptions.CreateOrClone(options); | |||||
var ids = new BucketIds(guildId: guildId); | |||||
return await SendAsync<Ban>("GET", () => $"guilds/{guildId}/bans/{userId}", ids, options: options).ConfigureAwait(false); | |||||
} | |||||
public async Task CreateGuildBanAsync(ulong guildId, ulong userId, CreateGuildBanParams args, RequestOptions options = null) | public async Task CreateGuildBanAsync(ulong guildId, ulong userId, CreateGuildBanParams args, RequestOptions options = null) | ||||
{ | { | ||||
Preconditions.NotEqual(guildId, 0, nameof(guildId)); | Preconditions.NotEqual(guildId, 0, nameof(guildId)); | ||||
@@ -1209,6 +1218,26 @@ namespace Discord.API | |||||
return await SendAsync<IReadOnlyCollection<VoiceRegion>>("GET", () => $"guilds/{guildId}/regions", ids, options: options).ConfigureAwait(false); | return await SendAsync<IReadOnlyCollection<VoiceRegion>>("GET", () => $"guilds/{guildId}/regions", ids, options: options).ConfigureAwait(false); | ||||
} | } | ||||
//Audit logs | |||||
public async Task<AuditLog> GetAuditLogsAsync(ulong guildId, GetAuditLogsParams args, RequestOptions options = null) | |||||
{ | |||||
Preconditions.NotEqual(guildId, 0, nameof(guildId)); | |||||
Preconditions.NotNull(args, nameof(args)); | |||||
options = RequestOptions.CreateOrClone(options); | |||||
int limit = args.Limit.GetValueOrDefault(int.MaxValue); | |||||
var ids = new BucketIds(guildId: guildId); | |||||
Expression<Func<string>> endpoint; | |||||
if (args.BeforeEntryId.IsSpecified) | |||||
endpoint = () => $"guilds/{guildId}/audit-logs?limit={limit}&before={args.BeforeEntryId.Value}"; | |||||
else | |||||
endpoint = () => $"guilds/{guildId}/audit-logs?limit={limit}"; | |||||
return await SendAsync<AuditLog>("GET", endpoint, ids, options: options).ConfigureAwait(false); | |||||
} | |||||
//Webhooks | //Webhooks | ||||
public async Task<Webhook> CreateWebhookAsync(ulong channelId, CreateWebhookParams args, RequestOptions options = null) | public async Task<Webhook> CreateWebhookAsync(ulong channelId, CreateWebhookParams args, RequestOptions options = null) | ||||
{ | { | ||||
@@ -0,0 +1,58 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using Model = Discord.API.AuditLog; | |||||
using EntryModel = Discord.API.AuditLogEntry; | |||||
namespace Discord.Rest | |||||
{ | |||||
internal static class AuditLogHelper | |||||
{ | |||||
private static readonly Dictionary<ActionType, Func<BaseDiscordClient, Model, EntryModel, IAuditLogData>> CreateMapping | |||||
= new Dictionary<ActionType, Func<BaseDiscordClient, Model, EntryModel, IAuditLogData>>() | |||||
{ | |||||
[ActionType.GuildUpdated] = GuildUpdateAuditLogData.Create, | |||||
[ActionType.ChannelCreated] = ChannelCreateAuditLogData.Create, | |||||
[ActionType.ChannelUpdated] = ChannelUpdateAuditLogData.Create, | |||||
[ActionType.ChannelDeleted] = ChannelDeleteAuditLogData.Create, | |||||
[ActionType.OverwriteCreated] = OverwriteCreateAuditLogData.Create, | |||||
[ActionType.OverwriteUpdated] = OverwriteUpdateAuditLogData.Create, | |||||
[ActionType.OverwriteDeleted] = OverwriteDeleteAuditLogData.Create, | |||||
[ActionType.Kick] = KickAuditLogData.Create, | |||||
[ActionType.Prune] = PruneAuditLogData.Create, | |||||
[ActionType.Ban] = BanAuditLogData.Create, | |||||
[ActionType.Unban] = UnbanAuditLogData.Create, | |||||
[ActionType.MemberUpdated] = MemberUpdateAuditLogData.Create, | |||||
[ActionType.MemberRoleUpdated] = MemberRoleAuditLogData.Create, | |||||
[ActionType.RoleCreated] = RoleCreateAuditLogData.Create, | |||||
[ActionType.RoleUpdated] = RoleUpdateAuditLogData.Create, | |||||
[ActionType.RoleDeleted] = RoleDeleteAuditLogData.Create, | |||||
[ActionType.InviteCreated] = InviteCreateAuditLogData.Create, | |||||
[ActionType.InviteUpdated] = InviteUpdateAuditLogData.Create, | |||||
[ActionType.InviteDeleted] = InviteDeleteAuditLogData.Create, | |||||
[ActionType.WebhookCreated] = WebhookCreateAuditLogData.Create, | |||||
[ActionType.WebhookUpdated] = WebhookUpdateAuditLogData.Create, | |||||
[ActionType.WebhookDeleted] = WebhookDeleteAuditLogData.Create, | |||||
[ActionType.EmojiCreated] = EmoteCreateAuditLogData.Create, | |||||
[ActionType.EmojiUpdated] = EmoteUpdateAuditLogData.Create, | |||||
[ActionType.EmojiDeleted] = EmoteDeleteAuditLogData.Create, | |||||
[ActionType.MessageDeleted] = MessageDeleteAuditLogData.Create, | |||||
}; | |||||
public static IAuditLogData CreateData(BaseDiscordClient discord, Model log, EntryModel entry) | |||||
{ | |||||
if (CreateMapping.TryGetValue(entry.Action, out var func)) | |||||
return func(discord, log, entry); | |||||
return null; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,23 @@ | |||||
using System.Linq; | |||||
using Model = Discord.API.AuditLog; | |||||
using EntryModel = Discord.API.AuditLogEntry; | |||||
namespace Discord.Rest | |||||
{ | |||||
public class BanAuditLogData : IAuditLogData | |||||
{ | |||||
private BanAuditLogData(IUser user) | |||||
{ | |||||
Target = user; | |||||
} | |||||
internal static BanAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) | |||||
{ | |||||
var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); | |||||
return new BanAuditLogData(RestUser.Create(discord, userInfo)); | |||||
} | |||||
public IUser Target { get; } | |||||
} | |||||
} |
@@ -0,0 +1,52 @@ | |||||
using Newtonsoft.Json.Linq; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using Model = Discord.API.AuditLog; | |||||
using EntryModel = Discord.API.AuditLogEntry; | |||||
namespace Discord.Rest | |||||
{ | |||||
public class ChannelCreateAuditLogData : IAuditLogData | |||||
{ | |||||
private ChannelCreateAuditLogData(ulong id, string name, ChannelType type, IReadOnlyCollection<Overwrite> overwrites) | |||||
{ | |||||
ChannelId = id; | |||||
ChannelName = name; | |||||
ChannelType = type; | |||||
Overwrites = overwrites; | |||||
} | |||||
internal static ChannelCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) | |||||
{ | |||||
var changes = entry.Changes; | |||||
var overwrites = new List<Overwrite>(); | |||||
var overwritesModel = changes.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites"); | |||||
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type"); | |||||
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); | |||||
var type = typeModel.NewValue.ToObject<ChannelType>(); | |||||
var name = nameModel.NewValue.ToObject<string>(); | |||||
foreach (var overwrite in overwritesModel.NewValue) | |||||
{ | |||||
var deny = overwrite.Value<ulong>("deny"); | |||||
var _type = overwrite.Value<string>("type"); | |||||
var id = overwrite.Value<ulong>("id"); | |||||
var allow = overwrite.Value<ulong>("allow"); | |||||
PermissionTarget permType = _type == "member" ? PermissionTarget.User : PermissionTarget.Role; | |||||
overwrites.Add(new Overwrite(id, permType, new OverwritePermissions(allow, deny))); | |||||
} | |||||
return new ChannelCreateAuditLogData(entry.TargetId.Value, name, type, overwrites.ToReadOnlyCollection()); | |||||
} | |||||
public ulong ChannelId { get; } | |||||
public string ChannelName { get; } | |||||
public ChannelType ChannelType { get; } | |||||
public IReadOnlyCollection<Overwrite> Overwrites { get; } | |||||
} | |||||
} |