Documentation Overhaul (#1161)

* Add XML docs

* Clean up style switcher

* Squash commits on branch docs/faq-n-patches

* Fix broken theme selector

* Add local image embed instruction

* Add a bunch of XML docs

* Add a bunch of XML docs

* Fix broken search
+ DocFX by default ships with an older version of jQuery, switching to a newer version confuses parts of the DocFX Javascript.

* Minor fixes for CONTRIBUTING.md and README.md

* Clean up filterConfig.yml

+ New config exposes Discord.Net namespace since it has several common public exceptions that may be helpful to users

* Add XML docs

* Read token from Environment Variable instead of hardcode

* Add XMLDocs

* Compress some assets & add OAuth2 URL generator

* Fix sample link & add missing pictures

* Add tag examples

* Fix embed docs consistency

* Add details regarding userbot support

* Add XML Docs

* Add XML Docs

* Add XML Docs

* Minor fixes in documentations
+ Fix unescaped '<'
+ Fix typo

* Fix seealso for preconditions and add missing descriptions

* Add missing exceptions

* Document exposed TypeReaders

* Fix letter-casing for files

* Add 'last modified' plugin

Source: https://github.com/Still34/DocFx.Plugin.LastModified
Licensed under MIT License

* XML Docs

* Fix minor consistencies & redundant impl

* Add properties examples to overwrite

* Fix missing Username prop

* Add warning for bulk-delete endpoint

* Replace note block

* Add BaseSocketClient docs

* Add XML docs

* Replace langword null to code block null instead

- Because DocFX sucks at rendering langword

* Replace all langword placements with code block

* Add more IGuild docs

* Add details to SpotifyGame

* Initial proofread of the articles

* Add explanation for RunMode

* Add event docs

- MessageReceived
- ChannelUpdated/Destroyed/Created

* Fix light theme link color

* Fix xml docs error

* Add partial documentation for audit log impl

* Add documentation for some REST-based objects

* Add partial documentation for audit log objects

* Add more XML comments to quotation mark alias map stuff, including an example

* Add reference to CommandServiceConfig from the util docs'

* Add explanation that if " is removed then it wont work

* Fix missing service provider in example

* Add documentation for new INestedChannel

* Add documentation

* Add documentation for new API version & few events

* Revise guide paragraphs/samples

+ Fix various formatting.
+ Provide a more detailed walkthrough for dependency injection.
+ Add C# note at intro.

* Fix typos & formatting

* Improve group module example

* Small amount to see if I'm doing it right

* Remove/cleanup redundant variables

* Fix EnterTypingState impl for doc inheritance

* Fix Test to resolve changes made in 15b58e

* Improve precondition documentation

+ Add precondition usage sample
+ Add precondition group usage sample
+ Move precondition samples to its own sample folder

* Move samples to individual folders

* Clarify token source

* Cleanup styling of README.md for docs

* Replace InvalidPathChars for NS1.3

* InvalidPathChars does not exist in NS1.3; replaced with GetInvalidPathChars instead.

* Add a missing change for 2c7cc738

* Update LastModified to v1.1.0 & add license

* Rewrite installation page for Core 2.1

* Fix anchor link

* Bump post-processor to v1.1.1

* Add fixes to partial file & add license

* Moved theme-switcher code to scripts partial file
+ Add author's MIT license to featherlight javascript

* Remove unused bootstrap plugin

* Bump LastModified plugin

* Changed the path from 'lastmodified' to 'last-modified' for consistency

* Cleanup README & Contribution guide

* Changes to last pr

* Fix GetCategoryAsync docs

* Proofread and cleanup articles

* Change passive voice in "Get Started" to active
* Fix improper preposition in Commands Introduction page
* Fix minor grammar mistakes in "Your First Bot" (future tense -> present tense/subjunctive mood -> indicative mood/proper noun casing/incorrect noun/add missing article)
* Fix minor grammar mistakes in "Installation" (missing article)

* no hablo ingles

* Try try try again

* I'm sure you're having as much fun as I am

* Cleanup TOC & fix titles

* Improve styling

+ Change title font to Noto Sans
+ Add materialized design for commit message box

* Add DescriptionGenerator plugin

* Add nightly section for clarification

* Fix typos in Nightlies & Post-execution

* Bump DescriptionGenerator to v1.1.0

+ This build adds the functionality of generating managed references' summary into the description tag.

* Initial emoji article draft

* Add 'additional information' section for emoji article

* Add cosmetic changes to the master css

* Alter info box color
+ Add transition to article content

* Add clarification in the emoji article

* Emphasize that normal emoji string will not translate to its Unicode representation.
* Clean up or add some of the samples featured in the article.
+ Add emoji/emote declaration section for clarification.
+ Add WebSocket emote sample.
- Remove inconsistent styling ('wacky memes' proves to be too out of place).

* Improve readability for nightlies article

* Move 'Bundled Preconditions' section

* Bump LastModified to fix UTC DateTime parsing

* Add langwordMapping.yml

* Add XML docs

* Add VSC workspace rule

* The root workspace limits the ruler to 120 characters for member documentations and excludes folders such as 'samples' and 'docs'.
* The docs workspace limits the ruler to 70 characters for standard conceptual article to comply with documentation's CONTRIBUTING.md rule, and excludes temprorary folders created by DocFX.

* Update CONTRIBUTING.md

* Add documentation style rule

* Fix styling of several member documentation

* Fix ' />' caused by Agent Smith oddities
* Fix styling to be more specific about the mention of IDs

* Fix exception summary to comply with official Microsoft Docs style

* References
https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception?view=netframework-4.7.2
https://docs.microsoft.com/en-us/dotnet/api/system.platformnotsupportedexception?view=netframework-4.7.2
https://docs.microsoft.com/en-us/dotnet/api/system.badimageformatexception?view=netframework-4.7.2

* Add XML documentations

* Shift color return docs

* Fix minor docs

* Added documentation for SocketDMChannel, SocketGuildChannel, and SocketTextChannel

* Add XML docs

* Corrections to SocketGuildChannel

* Corrections to SocketTextChannel

* Corrections to SocketDMChannel

* Swapped out 'id' for 'snowflake identifier

* Swapped out 'id' for 'snowflake identifier'

* SocketDMChannel amendments

* SocketGuildChannel amendments

* SocketTextChannel amendments

* Add XML docs & patch return types
+ Starting from this commit, all return types for tasks will use style similar to most documentations featured on docs.microsoft.com

References:
https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.dbcontext.-ctor?view=efcore-2.1
https://docs.microsoft.com/en-us/dotnet/api/system.io.filestream.readasync?view=netcore-2.1
https://docs.microsoft.com/en-us/dotnet/api/system.io.textwriter.writelineasync?view=netcore-2.1#System_IO_TextWriter_WriteLineAsync_System_Char___
And many more other asynchronous method documentations featured in the latest BCL.

* Added documentation for many audit log data types, fixed vowel indefinite articles

* Change audit log data types to start with 'Contains' (verb) instead of an article

* Fix some documentation issues and document some more audit log data types

* Fix English posession

* Add XML doc

* Documented two more types

* Documented RoleCreateAuditLogData

* Document remaining audit log data types

* Added RestDMChannel documentation

* Added RestGuildChannel documentation

* Added RestTextChannel documentation

* Added RestVoiceChannel documentation

* Added RestUser documentation

* Added RestRole documentation

* Added RestMessage documentation

* Slightly better wording

* Contains -> Contains a piece of (describe article)

* [EN] Present perf. -> past perf.

* Add XML docs

* Fix arrow alignment

* Clarify supported nullable type

* Fixed a typo in ISnowflakeEntity

* Added RestUser Documentation

* Added RestInvite documentation

* Add XML docs & minor optimizations

* Minor optimization for doc rendering

* Rollback font optimization changes

* Amendments to RestUser

* Added SocketDMChannel documentation

* Added RestDMChannel documentation

* Added RestGuild documentation

* Adjustment to SocketDMChannel

* Added minimal descriptions from the API documentation for Integration types

* Added obsolete mention to the ReadMessages flag.

* Added remarks about 2FA requirement for guild permissions

* Added xmldoc for GuildPermission methods

* Added xml doc for ToAllowList and ToDenyList

* Added specification of how the bits of the color raw value are packed

* Added discord API documentation to IConnection interface

* I can spell :^)

* Fix whitespace in ChannelPermission

* fix spacing of values in guildpermission

* Made changes to get field descriptions from feedback, added returns tag to IConnection

* Added property get standard for IntegrationAccount

* Added property get pattern to xml docs and identical returns tag.

* Change all color class references to struct
...because it isn't a class.

* Add XML docs

* Rewrote the returns tags in IGuildIntegration, removed the ones I was unsure about.

* Rewrote the rest of the returns tags

* Amendments

* Cleanup doc for c1d78189

* Added types to <returns> tags where missing

* Added second sample for adding reactions

* Added some class summaries

* Missed a period

* Amendments

* restored the removed line break

* Removed unnecessary see tag

* Use consistent quotation marks around subscribers, the name for these users are dependant on the source of where they are integrated from (youtube or twitch), so we should not use a name that is specific to one platform

* Add <remarks> tag to the IGuildIntegration xmldocs

* Fix grammar issue

* Update DescriptionGenerator

* Cleanup of https://github.com/Still34/Discord.Net/pull/8

* Cleanup previous PR

* Fix for misleading behaviour in the emoji guide
+ Original lines stated that sending a emoji wrapped in colon will not be parsed, but that was incorrect; replaced with reactions instead of sending messages as the example

* Add strings for dictionary in DotSettings

* Add XML docs

* Fix lots of typos in comments
+ Geez, I didn't know there were so many.

* Add XML docs & rewrite GetMessagesAsync docs

This commit rewrites the remarks section of GetMessagesAsync, as well as adding examples to several methods.

* Update 'Your First Bot'
+ This commit reflects the new changes made to the Discord Application Developer Portal after its major update

* Initial optimization for DocFX render & add missing files

* Add examples in message methods

* Cleanup https://github.com/RogueException/Discord.Net/pull/1128

* Fix first bot note

* Cleanup FAQ structure

* Add XML docs

* Update docfx plugins

* Fix navbar collapsing issue

* Fix broken xref

* Cleanup FAQ section
+ Add introductory paragraphs to each FAQ section.
+ Add 'missing dependency' entry to commands FAQ.
* Split commands FAQ to 'General' and 'DI' sections.

* Cleanup https://github.com/RogueException/Discord.Net/pull/1139

* Fix missing namespace

* Add missing highlighting css for the light theme

* Add additional clarification for installing packages

* Add indentation to example for clarity

* Cleanup several articles to be more human-friendly and easier to read

* Remove RPC-related notes

* Cleanup slow-mode-related documentation strings

* Add an additional note about cross-guild emote usage

* Add CreateTextChannel sample

* Add XMLDocs
This commit is contained in:
Still Hsu
2018-10-01 05:44:33 +08:00
committed by Christopher F
parent 6b21b11f7d
commit ff0fea98a6
498 changed files with 16064 additions and 2633 deletions

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
namespace Discord.Audio
@@ -7,8 +7,17 @@ namespace Discord.Audio
{
public override bool CanWrite => true;
public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
public override void SetLength(long value) { throw new NotSupportedException(); }
public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
/// <inheritdoc />
/// <exception cref="NotSupportedException">Reading this stream is not supported.</exception>
public override int Read(byte[] buffer, int offset, int count) =>
throw new NotSupportedException();
/// <inheritdoc />
/// <exception cref="NotSupportedException">Setting the length to this stream is not supported.</exception>
public override void SetLength(long value) =>
throw new NotSupportedException();
/// <inheritdoc />
/// <exception cref="NotSupportedException">Seeking this stream is not supported..</exception>
public override long Seek(long offset, SeekOrigin origin) =>
throw new NotSupportedException();
}
}

View File

@@ -11,10 +11,9 @@ namespace Discord.Audio
public override bool CanSeek => false;
public override bool CanWrite => false;
public virtual void WriteHeader(ushort seq, uint timestamp, bool missed)
{
throw new InvalidOperationException("This stream does not accept headers");
}
/// <exception cref="InvalidOperationException">This stream does not accept headers.</exception>
public virtual void WriteHeader(ushort seq, uint timestamp, bool missed) =>
throw new InvalidOperationException("This stream does not accept headers.");
public override void Write(byte[] buffer, int offset, int count)
{
WriteAsync(buffer, offset, count, CancellationToken.None).GetAwaiter().GetResult();
@@ -30,15 +29,30 @@ namespace Discord.Audio
public virtual Task ClearAsync(CancellationToken cancellationToken) { return Task.Delay(0); }
public override long Length { get { throw new NotSupportedException(); } }
/// <inheritdoc />
/// <exception cref="NotSupportedException">Reading stream length is not supported.</exception>
public override long Length =>
throw new NotSupportedException();
/// <inheritdoc />
/// <exception cref="NotSupportedException">Getting or setting this stream position is not supported.</exception>
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
public override void SetLength(long value) { throw new NotSupportedException(); }
public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
/// <inheritdoc />
/// <exception cref="NotSupportedException">Reading this stream is not supported.</exception>
public override int Read(byte[] buffer, int offset, int count) =>
throw new NotSupportedException();
/// <inheritdoc />
/// <exception cref="NotSupportedException">Setting the length to this stream is not supported.</exception>
public override void SetLength(long value) =>
throw new NotSupportedException();
/// <inheritdoc />
/// <exception cref="NotSupportedException">Seeking this stream is not supported..</exception>
public override long Seek(long offset, SeekOrigin origin) =>
throw new NotSupportedException();
}
}

View File

@@ -15,7 +15,7 @@ namespace Discord.Audio
/// <summary> Gets the current connection state of this client. </summary>
ConnectionState ConnectionState { get; }
/// <summary> Gets the estimated round-trip latency, in milliseconds, to the voice websocket server. </summary>
/// <summary> Gets the estimated round-trip latency, in milliseconds, to the voice WebSocket server. </summary>
int Latency { get; }
/// <summary> Gets the estimated round-trip latency, in milliseconds, to the voice UDP server. </summary>
int UdpLatency { get; }

View File

@@ -2,10 +2,32 @@ using System;
namespace Discord
{
/// <summary>
/// Represents a class containing the strings related to various Content Delivery Networks (CDNs).
/// </summary>
public static class CDN
{
/// <summary>
/// Returns an application icon URL.
/// </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)
=> iconId != null ? $"{DiscordConfig.CDNUrl}app-icons/{appId}/{iconId}.jpg" : null;
/// <summary>
/// Returns a user avatar URL.
/// </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)
{
if (avatarId == null)
@@ -13,27 +35,90 @@ namespace Discord
string extension = FormatToExtension(format, avatarId);
return $"{DiscordConfig.CDNUrl}avatars/{userId}/{avatarId}.{extension}?size={size}";
}
/// <summary>
/// Returns the default user avatar URL.
/// </summary>
/// <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)
{
return $"{DiscordConfig.CDNUrl}embed/avatars/{discriminator % 5}.png";
}
/// <summary>
/// Returns an icon URL.
/// </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)
=> iconId != null ? $"{DiscordConfig.CDNUrl}icons/{guildId}/{iconId}.jpg" : null;
/// <summary>
/// Returns a guild splash URL.
/// </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)
=> splashId != null ? $"{DiscordConfig.CDNUrl}splashes/{guildId}/{splashId}.jpg" : null;
/// <summary>
/// Returns a channel icon URL.
/// </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)
=> iconId != null ? $"{DiscordConfig.CDNUrl}channel-icons/{channelId}/{iconId}.jpg" : null;
/// <summary>
/// Returns an emoji URL.
/// </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)
=> $"{DiscordConfig.CDNUrl}emojis/{emojiId}.{(animated ? "gif" : "png")}";
/// <summary>
/// Returns a Rich Presence asset URL.
/// </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)
{
string extension = FormatToExtension(format, "");
return $"{DiscordConfig.CDNUrl}app-assets/{appId}/{assetId}.{extension}?size={size}";
}
/// <summary>
/// Returns a Spotify album URL.
/// </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)
=> $"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)
=> $"https://open.spotify.com/track/{trackId}";

View File

@@ -1,11 +1,29 @@
namespace Discord.Commands
namespace Discord.Commands
{
/// <summary>
/// Represents a context of a command. This may include the client, guild, channel, user, and message.
/// </summary>
public interface ICommandContext
{
/// <summary>
/// Gets the <see cref="IDiscordClient" /> that the command is executed with.
/// </summary>
IDiscordClient Client { get; }
/// <summary>
/// Gets the <see cref="IGuild" /> that the command is executed in.
/// </summary>
IGuild Guild { get; }
/// <summary>
/// Gets the <see cref="IMessageChannel" /> that the command is executed in.
/// </summary>
IMessageChannel Channel { get; }
/// <summary>
/// Gets the <see cref="IUser" /> who executed the command.
/// </summary>
IUser User { get; }
/// <summary>
/// Gets the <see cref="IUserMessage" /> that the command is interpreted from.
/// </summary>
IUserMessage Message { get; }
}
}

View File

@@ -1,10 +1,15 @@
namespace Discord
namespace Discord
{
/// <summary> Specifies the connection state of a client. </summary>
public enum ConnectionState : byte
{
/// <summary> The client has disconnected from Discord. </summary>
Disconnected,
/// <summary> The client is connecting to Discord. </summary>
Connecting,
/// <summary> The client has established a connection to Discord. </summary>
Connected,
/// <summary> The client is disconnecting from Discord. </summary>
Disconnecting
}
}

View File

@@ -2,35 +2,143 @@ using System.Reflection;
namespace Discord
{
/// <summary>
/// Defines various behaviors of Discord.Net.
/// </summary>
public class DiscordConfig
{
/// <summary>
/// Returns the API version Discord.Net uses.
/// </summary>
/// <returns>
/// An <see cref="int"/> 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;
/// <summary>
/// Returns the Voice API version Discord.Net uses.
/// </summary>
/// <returns>
/// An <see cref="int"/> representing the API version that Discord.Net uses to communicate with Discord's
/// voice server.
/// </returns>
public const int VoiceAPIVersion = 3;
/// <summary>
/// Gets the Discord.Net version, including the build number.
/// </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; } =
typeof(DiscordConfig).GetTypeInfo().Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ??
typeof(DiscordConfig).GetTypeInfo().Assembly.GetName().Version.ToString(3) ??
"Unknown";
/// <summary>
/// Gets the user agent that Discord.Net uses in its clients.
/// </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})";
/// <summary>
/// Returns the base Discord API URL.
/// </summary>
/// <returns>
/// The Discord API URL using <see cref="APIVersion"/>.
/// </returns>
public static readonly string APIUrl = $"https://discordapp.com/api/v{APIVersion}/";
/// <summary>
/// Returns the base Discord CDN URL.
/// </summary>
/// <returns>
/// The base Discord Content Delivery Network (CDN) URL.
/// </returns>
public const string CDNUrl = "https://cdn.discordapp.com/";
/// <summary>
/// Returns the base Discord invite URL.
/// </summary>
/// <returns>
/// The base Discord invite URL.
/// </returns>
public const string InviteUrl = "https://discord.gg/";
/// <summary>
/// Returns the default timeout for requests.
/// </summary>
/// <returns>
/// The amount of time it takes in milliseconds before a request is timed out.
/// </returns>
public const int DefaultRequestTimeout = 15000;
/// <summary>
/// Returns the max length for a Discord message.
/// </summary>
/// <returns>
/// The maximum length of a message allowed by Discord.
/// </returns>
public const int MaxMessageSize = 2000;
/// <summary>
/// Returns the max messages allowed to be in a request.
/// </summary>
/// <returns>
/// The maximum number of messages that can be gotten per-batch.
/// </returns>
public const int MaxMessagesPerBatch = 100;
/// <summary>
/// Returns the max users allowed to be in a request.
/// </summary>
/// <returns>
/// The maximum number of users that can be gotten per-batch.
/// </returns>
public const int MaxUsersPerBatch = 1000;
/// <summary>
/// Returns the max guilds allowed to be in a request.
/// </summary>
/// <returns>
/// The maximum number of guilds that can be gotten per-batch.
/// </returns>
public const int MaxGuildsPerBatch = 100;
/// <summary>
/// Returns the max user reactions allowed to be in a request.
/// </summary>
/// <returns>
/// The maximum number of user reactions that can be gotten per-batch.
/// </returns>
public const int MaxUserReactionsPerBatch = 100;
/// <summary>
/// Returns the max audit log entries allowed to be in a request.
/// </summary>
/// <returns>
/// The maximum number of audit log entries that can be gotten per-batch.
/// </returns>
public const int MaxAuditLogEntriesPerBatch = 100;
/// <summary> Gets or sets how a request should act in the case of an error, by default. </summary>
/// <summary>
/// Gets or sets how a request should act in the case of an error, by default.
/// </summary>
/// <returns>
/// The currently set <see cref="RetryMode"/>.
/// </returns>
public RetryMode DefaultRetryMode { get; set; } = RetryMode.AlwaysRetry;
/// <summary> Gets or sets the minimum log level severity that will be sent to the Log event. </summary>
/// <summary>
/// Gets or sets the minimum log level severity that will be sent to the Log event.
/// </summary>
/// <returns>
/// The currently set <see cref="LogSeverity"/> for logging level.
/// </returns>
public LogSeverity LogLevel { get; set; } = LogSeverity.Info;
/// <summary> Gets or sets whether the initial log entry should be printed. </summary>
/// <summary>
/// Gets or sets whether the initial log entry should be printed.
/// </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;
}
}

View File

@@ -1,10 +1,25 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Specifies a Discord user's activity type.
/// </summary>
public enum ActivityType
{
/// <summary>
/// The user is playing a game.
/// </summary>
Playing = 0,
/// <summary>
/// The user is streaming online.
/// </summary>
Streaming = 1,
/// <summary>
/// The user is listening to a song.
/// </summary>
Listening = 2,
/// <summary>
/// The user is watching a media.
/// </summary>
Watching = 3
}
}

View File

@@ -2,19 +2,30 @@ using System.Diagnostics;
namespace Discord
{
/// <summary>
/// A user's game status.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class Game : IActivity
{
/// <inheritdoc/>
public string Name { get; internal set; }
/// <inheritdoc/>
public ActivityType Type { get; internal set; }
internal Game() { }
/// <summary>
/// Creates a <see cref="Game"/> with the provided <paramref name="name"/> and <see cref="ActivityType"/>.
/// </summary>
/// <param name="name">The name of the game.</param>
/// <param name="type">The type of activity. Default is <see cref="Discord.ActivityType.Playing"/>.</param>
public Game(string name, ActivityType type = ActivityType.Playing)
{
Name = name;
Type = type;
}
/// <summary> Returns the name of the <see cref="Game"/>. </summary>
public override string ToString() => Name;
private string DebuggerDisplay => Name;
}

View File

@@ -1,14 +1,37 @@
namespace Discord
{
/// <summary>
/// An asset for a <see cref="RichGame" /> object containing the text and image.
/// </summary>
public class GameAsset
{
internal GameAsset() { }
internal ulong? ApplicationId { get; set; }
/// <summary>
/// Gets the description of the asset.
/// </summary>
/// <returns>
/// A string containing the description of the asset.
/// </returns>
public string Text { get; internal set; }
/// <summary>
/// Gets the image ID of the asset.
/// </summary>
/// <returns>
/// A string containing the unique image identifier of the asset.
/// </returns>
public string ImageId { get; internal set; }
/// <summary>
/// Returns the image URL of the asset.
/// </summary>
/// <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 string pointing to the image URL of the asset; <c>null</c> when the application ID does not exist.
/// </returns>
public string GetImageUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128)
=> ApplicationId.HasValue ? CDN.GetRichAssetUrl(ApplicationId.Value, ImageId, size, format) : null;
}

View File

@@ -1,11 +1,26 @@
namespace Discord
{
/// <summary>
/// Party information for a <see cref="RichGame" /> object.
/// </summary>
public class GameParty
{
internal GameParty() { }
/// <summary>
/// Gets the ID of the party.
/// </summary>
/// <returns>
/// A string containing the unique identifier of the party.
/// </returns>
public string Id { get; internal set; }
public long Members { get; internal set; }
/// <summary>
/// Gets the party's current and maximum size.
/// </summary>
/// <returns>
/// A <see cref="long"/> representing the capacity of the party.
/// </returns>
public long Capacity { get; internal set; }
}
}

View File

@@ -1,9 +1,21 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Party secret for a <see cref="RichGame" /> object.
/// </summary>
public class GameSecrets
{
/// <summary>
/// Gets the secret for a specific instanced match.
/// </summary>
public string Match { get; }
/// <summary>
/// Gets the secret for joining a party.
/// </summary>
public string Join { get; }
/// <summary>
/// Gets the secret for spectating a game.
/// </summary>
public string Spectate { get; }
internal GameSecrets(string match, string join, string spectate)
@@ -13,4 +25,4 @@
Spectate = spectate;
}
}
}
}

View File

@@ -1,10 +1,19 @@
using System;
using System;
namespace Discord
{
/// <summary>
/// Timestamps for a <see cref="RichGame" /> object.
/// </summary>
public class GameTimestamps
{
/// <summary>
/// Gets when the activity started.
/// </summary>
public DateTimeOffset? Start { get; }
/// <summary>
/// Gets when the activity ends.
/// </summary>
public DateTimeOffset? End { get; }
internal GameTimestamps(DateTimeOffset? start, DateTimeOffset? end)
@@ -13,4 +22,4 @@ namespace Discord
End = end;
}
}
}
}

View File

@@ -1,8 +1,23 @@
namespace Discord
namespace Discord
{
/// <summary>
/// A user's activity status, typically a <see cref="Game"/>.
/// </summary>
public interface IActivity
{
/// <summary>
/// Gets the name of the activity.
/// </summary>
/// <returns>
/// A string containing the name of the activity that the user is doing.
/// </returns>
string Name { get; }
/// <summary>
/// Gets the type of the activity.
/// </summary>
/// <returns>
/// The type of activity.
/// </returns>
ActivityType Type { get; }
}
}

View File

@@ -2,20 +2,50 @@ using System.Diagnostics;
namespace Discord
{
/// <summary>
/// A user's Rich Presence status.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RichGame : Game
{
internal RichGame() { }
/// <summary>
/// Gets what the player is currently doing.
/// </summary>
public string Details { get; internal set; }
/// <summary>
/// Gets the user's current party status.
/// </summary>
public string State { get; internal set; }
/// <summary>
/// Gets the application ID for the game.
/// </summary>
public ulong ApplicationId { get; internal set; }
/// <summary>
/// Gets the small image for the presence and their hover texts.
/// </summary>
public GameAsset SmallAsset { get; internal set; }
/// <summary>
/// Gets the large image for the presence and their hover texts.
/// </summary>
public GameAsset LargeAsset { get; internal set; }
/// <summary>
/// Gets the information for the current party of the player.
/// </summary>
public GameParty Party { get; internal set; }
/// <summary>
/// Gets the secrets for Rich Presence joining and spectating.
/// </summary>
public GameSecrets Secrets { get; internal set; }
/// <summary>
/// Gets the timestamps for start and/or end of the game.
/// </summary>
public GameTimestamps Timestamps { get; internal set; }
/// <summary>
/// Returns the name of the Rich Presence.
/// </summary>
public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} (Rich)";
}

View File

@@ -4,22 +4,85 @@ using System.Diagnostics;
namespace Discord
{
/// <summary>
/// A user's activity for listening to a song on Spotify.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class SpotifyGame : Game
{
/// <summary>
/// Gets the song's artist(s).
/// </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; }
/// <summary>
/// Gets the Spotify album title of the song.
/// </summary>
/// <returns>
/// A string containing the name of the album (e.g. <c>AVĪCI (01)</c>).
/// </returns>
public string AlbumTitle { get; internal set; }
/// <summary>
/// Gets the track title of the song.
/// </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; }
/// <summary>
/// Gets the duration of the song.
/// </summary>
/// <returns>
/// A <see cref="TimeSpan"/> containing the duration of the song.
/// </returns>
public TimeSpan? Duration { get; internal set; }
/// <summary>
/// Gets the track ID of the song.
/// </summary>
/// <returns>
/// A string containing the Spotify ID of the track (e.g. <c>7DoN0sCGIT9IcLrtBDm4f0</c>).
/// </returns>
public string TrackId { get; internal set; }
/// <summary>
/// Gets the session ID of the song.
/// </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; }
/// <summary>
/// Gets the URL of the album art.
/// </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; }
/// <summary>
/// Gets the direct Spotify URL of the track.
/// </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; }
internal SpotifyGame() { }
/// <summary>
/// Gets the full information of the song.
/// </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})";
private string DebuggerDisplay => $"{Name} (Spotify)";
}

View File

@@ -1,12 +1,23 @@
using System.Diagnostics;
using System.Diagnostics;
namespace Discord
{
/// <summary>
/// A user's activity for streaming on services such as Twitch.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class StreamingGame : Game
{
/// <summary>
/// Gets the URL of the stream.
/// </summary>
public string Url { get; internal set; }
/// <summary>
/// Creates a new <see cref="StreamingGame" /> based on the <paramref name="name"/> on the stream URL.
/// </summary>
/// <param name="name">The name of the stream.</param>
/// <param name="url">The URL of the stream.</param>
public StreamingGame(string name, string url)
{
Name = name;
@@ -14,7 +25,10 @@ namespace Discord
Type = ActivityType.Streaming;
}
/// <summary>
/// Gets the name of the stream.
/// </summary>
public override string ToString() => Name;
private string DebuggerDisplay => $"{Name} ({Url})";
}
}
}

View File

@@ -1,50 +1,122 @@
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"/>
/// Representing a type of action within an <see cref="IAuditLogEntry"/>.
/// </summary>
public enum ActionType
{
/// <summary>
/// this guild was updated.
/// </summary>
GuildUpdated = 1,
/// <summary>
/// A channel was created.
/// </summary>
ChannelCreated = 10,
/// <summary>
/// A channel was updated.
/// </summary>
ChannelUpdated = 11,
/// <summary>
/// A channel was deleted.
/// </summary>
ChannelDeleted = 12,
/// <summary>
/// A permission overwrite was created for a channel.
/// </summary>
OverwriteCreated = 13,
/// <summary>
/// A permission overwrite was updated for a channel.
/// </summary>
OverwriteUpdated = 14,
/// <summary>
/// A permission overwrite was deleted for a channel.
/// </summary>
OverwriteDeleted = 15,
/// <summary>
/// A user was kicked from this guild.
/// </summary>
Kick = 20,
/// <summary>
/// A prune took place in this guild.
/// </summary>
Prune = 21,
/// <summary>
/// A user banned another user from this guild.
/// </summary>
Ban = 22,
/// <summary>
/// A user unbanned another user from this guild.
/// </summary>
Unban = 23,
/// <summary>
/// A guild member whose information was updated.
/// </summary>
MemberUpdated = 24,
/// <summary>
/// A guild member's role collection was updated.
/// </summary>
MemberRoleUpdated = 25,
/// <summary>
/// A role was created in this guild.
/// </summary>
RoleCreated = 30,
/// <summary>
/// A role was updated in this guild.
/// </summary>
RoleUpdated = 31,
/// <summary>
/// A role was deleted from this guild.
/// </summary>
RoleDeleted = 32,
/// <summary>
/// An invite was created in this guild.
/// </summary>
InviteCreated = 40,
/// <summary>
/// An invite was updated in this guild.
/// </summary>
InviteUpdated = 41,
/// <summary>
/// An invite was deleted from this guild.
/// </summary>
InviteDeleted = 42,
/// <summary>
/// A Webhook was created in this guild.
/// </summary>
WebhookCreated = 50,
/// <summary>
/// A Webhook was updated in this guild.
/// </summary>
WebhookUpdated = 51,
/// <summary>
/// A Webhook was deleted from this guild.
/// </summary>
WebhookDeleted = 52,
/// <summary>
/// An emoji was created in this guild.
/// </summary>
EmojiCreated = 60,
/// <summary>
/// An emoji was updated in this guild.
/// </summary>
EmojiUpdated = 61,
/// <summary>
/// An emoji was deleted from this guild.
/// </summary>
EmojiDeleted = 62,
/// <summary>
/// A message was deleted from this guild.
/// </summary>
MessageDeleted = 72
}
}

View File

@@ -1,13 +1,7 @@
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"/>
/// Represents data applied to an <see cref="IAuditLogEntry"/>.
/// </summary>
public interface IAuditLogData
{ }

View File

@@ -7,28 +7,40 @@ using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents an entry in an audit log
/// Represents a generic audit log entry.
/// </summary>
public interface IAuditLogEntry : ISnowflakeEntity
{
/// <summary>
/// The action which occured to create this entry
/// Gets the action which occurred to create this entry.
/// </summary>
/// <returns>
/// The type of action for this audit log entry.
/// </returns>
ActionType Action { get; }
/// <summary>
/// The data for this entry. May be <see cref="null"/> if no data was available.
/// Gets the data for this entry.
/// </summary>
/// <returns>
/// An <see cref="IAuditLogData" /> for this audit log entry; <c>null</c> if no data is available.
/// </returns>
IAuditLogData Data { get; }
/// <summary>
/// The user responsible for causing the changes
/// Gets the user responsible for causing the changes.
/// </summary>
/// <returns>
/// A user object.
/// </returns>
IUser User { get; }
/// <summary>
/// The reason behind the change. May be <see cref="null"/> if no reason was provided.
/// Gets the reason behind the change.
/// </summary>
/// <returns>
/// A string containing the reason for the change; <c>null</c> if none is provided.
/// </returns>
string Reason { get; }
}
}

View File

@@ -1,8 +1,17 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Specifies the cache mode that should be used.
/// </summary>
public enum CacheMode
{
/// <summary>
/// Allows the object to be downloaded if it does not exist in the current cache.
/// </summary>
AllowDownload,
/// <summary>
/// Only allows the object to be pulled from the existing cache.
/// </summary>
CacheOnly
}
}

View File

@@ -1,11 +1,17 @@
namespace Discord
namespace Discord
{
/// <summary> Defines the types of channels. </summary>
public enum ChannelType
{
/// <summary> The channel is a text channel. </summary>
Text = 0,
/// <summary> The channel is a Direct Message channel. </summary>
DM = 1,
/// <summary> The channel is a voice channel. </summary>
Voice = 2,
/// <summary> The channel is a group channel. </summary>
Group = 3,
/// <summary> The channel is a category channel. </summary>
Category = 4
}
}

View File

@@ -1,9 +1,21 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Specifies the direction of where message(s) should be gotten from.
/// </summary>
public enum Direction
{
/// <summary>
/// The message(s) should be retrieved before a message.
/// </summary>
Before,
/// <summary>
/// The message(s) should be retrieved after a message.
/// </summary>
After,
/// <summary>
/// The message(s) should be retrieved around a message.
/// </summary>
Around
}
}

View File

@@ -1,33 +1,28 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Modify an IGuildChannel with the specified changes.
/// Properties that are used to modify an <see cref="IGuildChannel" /> with the specified changes.
/// </summary>
/// <example>
/// <code language="c#">
/// await (Context.Channel as ITextChannel)?.ModifyAsync(x =>
/// {
/// x.Name = "do-not-enter";
/// });
/// </code>
/// </example>
/// <seealso cref="IGuildChannel.ModifyAsync"/>
public class GuildChannelProperties
{
/// <summary>
/// Set the channel to this name
/// Gets or sets the channel to this name.
/// </summary>
/// <remarks>
/// When modifying an ITextChannel, the Name MUST be alphanumeric with dashes.
/// It must match the following RegEx: [a-z0-9-_]{2,100}
/// This property defines the new name for this channel.
/// <note type="warning">
/// When modifying an <see cref="ITextChannel"/>, the <see cref="Name"/> must be alphanumeric with
/// dashes. It must match the RegEx <c>[a-z0-9-_]{2,100}</c>.
/// </note>
/// </remarks>
/// <exception cref="Net.HttpException">A BadRequest will be thrown if the name does not match the above RegEx.</exception>
public Optional<string> Name { get; set; }
/// <summary>
/// Move the channel to the following position. This is 0-based!
/// Moves the channel to the following position. This property is zero-based.
/// </summary>
public Optional<int> Position { get; set; }
/// <summary>
/// Sets the category for this channel
/// Gets or sets the category ID for this channel.
/// </summary>
public Optional<ulong?> CategoryId { get; set; }
}

View File

@@ -1,15 +1,31 @@
using Discord.Audio;
using System;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents a generic audio channel.
/// </summary>
public interface IAudioChannel : IChannel
{
/// <summary> Connects to this audio channel. </summary>
/// <summary>
/// Connects to this audio channel.
/// </summary>
/// <param name="selfDeaf">Determines whether the client should deaf itself upon connection.</param>
/// <param name="selfMute">Determines whether the client should mute itself upon connection.</param>
/// <param name="external">Determines whether the audio client is an external one or not.</param>
/// <returns>
/// A task representing the asynchronous connection operation. The task result contains the
/// <see cref="IAudioClient"/> responsible for the connection.
/// </returns>
Task<IAudioClient> ConnectAsync(bool selfDeaf = false, bool selfMute = false, bool external = false);
/// <summary> Disconnects from this audio channel. </summary>
/// <summary>
/// Disconnects from this audio channel.
/// </summary>
/// <returns>
/// A task representing the asynchronous operation for disconnecting from the audio channel.
/// </returns>
Task DisconnectAsync();
}
}

View File

@@ -1,11 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents a generic category channel.
/// </summary>
public interface ICategoryChannel : IGuildChannel
{
}

View File

@@ -1,17 +1,43 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents a generic channel.
/// </summary>
public interface IChannel : ISnowflakeEntity
{
/// <summary> Gets the name of this channel. </summary>
/// <summary>
/// Gets the name of this channel.
/// </summary>
/// <returns>
/// A string containing the name of this channel.
/// </returns>
string Name { get; }
/// <summary> Gets a collection of all users in this channel. </summary>
/// <summary>
/// Gets a collection of all users in this channel.
/// </summary>
/// <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>
/// <returns>
/// A paged collection containing a collection of users that can access this channel. Flattening the
/// paginated response into a collection of users with
/// <see cref="AsyncEnumerableExtensions.FlattenAsync{T}"/> is required if you wish to access the users.
/// </returns>
IAsyncEnumerable<IReadOnlyCollection<IUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a user in this channel with the provided id. </summary>
/// <summary>
/// Gets a user in this channel.
/// </summary>
/// <param name="id">The snowflake identifier of the user (e.g. <c>168693960628371456</c>).</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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a user object that
/// represents the found user; <c>null</c> if none is found.
/// </returns>
Task<IUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
}
}

View File

@@ -1,13 +1,27 @@
using System.Threading.Tasks;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents a generic direct-message channel.
/// </summary>
public interface IDMChannel : IMessageChannel, IPrivateChannel
{
/// <summary> Gets the recipient of all messages in this channel. </summary>
/// <summary>
/// Gets the recipient of all messages in this channel.
/// </summary>
/// <returns>
/// A user object that represents the other user in this channel.
/// </returns>
IUser Recipient { get; }
/// <summary> Closes this private channel, removing it from your channel list. </summary>
/// <summary>
/// Closes this private channel, removing it from your channel list.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous close operation.
/// </returns>
Task CloseAsync(RequestOptions options = null);
}
}
}

View File

@@ -1,10 +1,19 @@
using System.Threading.Tasks;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents a generic private group channel.
/// </summary>
public interface IGroupChannel : IMessageChannel, IPrivateChannel, IAudioChannel
{
/// <summary> Leaves this group. </summary>
/// <summary>
/// Leaves this group.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous leave operation.
/// </returns>
Task LeaveAsync(RequestOptions options = null);
}
}
}

View File

@@ -4,45 +4,172 @@ using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents a generic guild channel.
/// </summary>
/// <seealso cref="ITextChannel"/>
/// <seealso cref="IVoiceChannel"/>
/// <seealso cref="ICategoryChannel"/>
public interface IGuildChannel : IChannel, IDeletable
{
/// <summary> Gets the position of this channel in the guild's channel list, relative to others of the same type. </summary>
/// <summary>
/// Gets the position of this channel.
/// </summary>
/// <returns>
/// An <see cref="int"/> representing the position of this channel in the guild's channel list relative to
/// others of the same type.
/// </returns>
int Position { get; }
/// <summary> Gets the guild this channel is a member of. </summary>
/// <summary>
/// Gets the guild associated with this channel.
/// </summary>
/// <returns>
/// A guild object that this channel belongs to.
/// </returns>
IGuild Guild { get; }
/// <summary> Gets the id of the guild this channel is a member of. </summary>
/// <summary>
/// Gets the guild ID associated with this channel.
/// </summary>
/// <returns>
/// An <see cref="ulong"/> representing the guild snowflake identifier for the guild that this channel
/// belongs to.
/// </returns>
ulong GuildId { get; }
/// <summary> Gets a collection of permission overwrites for this channel. </summary>
/// <summary>
/// Gets a collection of permission overwrites for this channel.
/// </summary>
/// <returns>
/// A collection of overwrites associated with this channel.
/// </returns>
IReadOnlyCollection<Overwrite> PermissionOverwrites { get; }
/// <summary> Creates a new invite to this channel. </summary>
/// <param name="maxAge"> The time (in seconds) until the invite expires. Set to null to never expire. </param>
/// <param name="maxUses"> The max amount of times this invite may be used. Set to null to have unlimited uses. </param>
/// <param name="isTemporary"> If true, a user accepting this invite will be kicked from the guild after closing their client. </param>
/// <summary>
/// Creates a new invite to this channel.
/// </summary>
/// <example>
/// The following example creates a new invite to this channel; the invite lasts for 12 hours and can only
/// be used 3 times throughout its lifespan.
/// <code language="cs">
/// await guildChannel.CreateInviteAsync(maxAge: 43200, maxUses: 3);
/// </code>
/// </example>
/// <param name="maxAge">The time (in seconds) until the invite expires. Set to <c>null</c> to never expire.</param>
/// <param name="maxUses">The max amount of times this invite may be used. Set to <c>null</c> to have unlimited uses.</param>
/// <param name="isTemporary">If <c>true</c>, the user accepting this invite will be kicked from the guild after closing their client.</param>
/// <param name="isUnique">If <c>true</c>, don't try to reuse a similar invite (useful for creating many unique one time use invites).</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous invite creation operation. The task result contains an invite
/// metadata object containing information for the created invite.
/// </returns>
Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null);
/// <summary> Returns a collection of all invites to this channel. </summary>
/// <summary>
/// Gets a collection of all invites to this channel.
/// </summary>
/// <example>
/// The following example gets all of the invites that have been created in this channel and selects the
/// most used invite.
/// <code language="cs">
/// var invites = await channel.GetInvitesAsync();
/// if (invites.Count == 0) return;
/// var invite = invites.OrderByDescending(x => x.Uses).FirstOrDefault();
/// </code>
/// </example>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection
/// of invite metadata that are created for this channel.
/// </returns>
Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null);
/// <summary> Modifies this guild channel. </summary>
/// <summary>
/// Modifies this guild channel.
/// </summary>
/// <param name="func">The delegate containing the properties to modify the channel with.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous modification operation.
/// </returns>
Task ModifyAsync(Action<GuildChannelProperties> func, RequestOptions options = null);
/// <summary> Gets the permission overwrite for a specific role, or null if one does not exist. </summary>
/// <summary>
/// Gets the permission overwrite for a specific role.
/// </summary>
/// <param name="role">The role to get the overwrite from.</param>
/// <returns>
/// An overwrite object for the targeted role; <c>null</c> if none is set.
/// </returns>
OverwritePermissions? GetPermissionOverwrite(IRole role);
/// <summary> Gets the permission overwrite for a specific user, or null if one does not exist. </summary>
/// <summary>
/// Gets the permission overwrite for a specific user.
/// </summary>
/// <param name="user">The user to get the overwrite from.</param>
/// <returns>
/// An overwrite object for the targeted user; <c>null</c> if none is set.
/// </returns>
OverwritePermissions? GetPermissionOverwrite(IUser user);
/// <summary> Removes the permission overwrite for the given role, if one exists. </summary>
/// <summary>
/// Removes the permission overwrite for the given role, if one exists.
/// </summary>
/// <param name="role">The role to remove the overwrite from.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task representing the asynchronous operation for removing the specified permissions from the channel.
/// </returns>
Task RemovePermissionOverwriteAsync(IRole role, RequestOptions options = null);
/// <summary> Removes the permission overwrite for the given user, if one exists. </summary>
/// <summary>
/// Removes the permission overwrite for the given user, if one exists.
/// </summary>
/// <param name="user">The user to remove the overwrite from.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task representing the asynchronous operation for removing the specified permissions from the channel.
/// </returns>
Task RemovePermissionOverwriteAsync(IUser user, RequestOptions options = null);
/// <summary> Adds or updates the permission overwrite for the given role. </summary>
/// <summary>
/// Adds or updates the permission overwrite for the given role.
/// </summary>
/// <param name="role">The role to add the overwrite to.</param>
/// <param name="permissions">The overwrite to add to the role.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task representing the asynchronous permission operation for adding the specified permissions to the channel.
/// </returns>
Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null);
/// <summary> Adds or updates the permission overwrite for the given user. </summary>
/// <summary>
/// Adds or updates the permission overwrite for the given user.
/// </summary>
/// <param name="user">The user to add the overwrite to.</param>
/// <param name="permissions">The overwrite to add to the user.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task representing the asynchronous permission operation for adding the specified permissions to the channel.
/// </returns>
Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions, RequestOptions options = null);
/// <summary> Gets a collection of all users in this channel. </summary>
/// <summary>
/// Gets a collection of users that are able to view the channel.
/// </summary>
/// <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>
/// <returns>
/// A paged collection containing a collection of guild users that can access this channel. Flattening the
/// paginated response into a collection of users with
/// <see cref="AsyncEnumerableExtensions.FlattenAsync{T}"/> is required if you wish to access the users.
/// </returns>
new IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a user in this channel with the provided id.</summary>
/// <summary>
/// Gets a user in this channel.
/// </summary>
/// <param name="id">The snowflake identifier of the user.</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>
/// <returns>
/// A task representing the asynchronous get operation. The task result contains a guild user object that
/// represents the user; <c>null</c> if none is found.
/// </returns>
new Task<IGuildUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
}
}

View File

@@ -5,38 +5,276 @@ using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents a generic channel that can send and receive messages.
/// </summary>
public interface IMessageChannel : IChannel
{
/// <summary> Sends a message to this message channel. </summary>
/// <summary>
/// Sends a message to this message channel.
/// </summary>
/// <example>
/// The following example sends a message with the current system time in RFC 1123 format to the channel and
/// deletes itself after 5 seconds.
/// <code language="cs">
/// var message = await channel.SendMessageAsync(DateTimeOffset.UtcNow.ToString("R"));
/// await Task.Delay(TimeSpan.FromSeconds(5))
/// .ContinueWith(x => message.DeleteAsync());
/// </code>
/// </example>
/// <param name="text">The message to be sent.</param>
/// <param name="isTTS">Determines whether the message should be read aloud by Discord or not.</param>
/// <param name="embed">The <see cref="Discord.EmbedType.Rich"/> <see cref="Embed"/> to be sent.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents an asynchronous send operation for delivering the message. The task result
/// contains the sent message.
/// </returns>
Task<IUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null);
/// <summary> Sends a file to this text channel, with an optional caption. </summary>
/// <summary>
/// Sends a file to this message channel with an optional caption.
/// </summary>
/// <example>
/// The following example uploads a local file called <c>wumpus.txt</c> along with the text
/// <c>good discord boi</c> to the channel.
/// <code language="cs">
/// await channel.SendFileAsync("wumpus.txt", "good discord boi");
/// </code>
///
/// The following example uploads a local image called <c>b1nzy.jpg</c> embedded inside a rich embed to the
/// channel.
/// <code language="cs">
/// await channel.SendFileAsync("b1nzy.jpg",
/// embed: new EmbedBuilder {ImageUrl = "attachment://b1nzy.jpg"}.Build());
/// </code>
/// </example>
/// <remarks>
/// This method sends a file as if you are uploading an attachment directly from your Discord client.
/// <note>
/// If you wish to upload an image and have it embedded in a <see cref="Discord.EmbedType.Rich"/> embed,
/// you may upload the file and refer to the file with "attachment://filename.ext" in the
/// <see cref="Discord.EmbedBuilder.ImageUrl"/>. See the example section for its usage.
/// </note>
/// </remarks>
/// <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="Discord.EmbedType.Rich" /> <see cref="Embed" /> to be sent.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents an asynchronous send operation for delivering the message. The task result
/// contains the sent message.
/// </returns>
Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null);
/// <summary> Sends a file to this text channel, with an optional caption. </summary>
/// <summary>
/// Sends a file to this message channel with an optional caption.
/// </summary>
/// <example>
/// The following example uploads a streamed image that will be called <c>b1nzy.jpg</c> embedded inside a
/// rich embed to the channel.
/// <code language="cs">
/// await channel.SendFileAsync(b1nzyStream, "b1nzy.jpg",
/// embed: new EmbedBuilder {ImageUrl = "attachment://b1nzy.jpg"}.Build());
/// </code>
/// </example>
/// <remarks>
/// This method sends a file as if you are uploading an attachment directly from your Discord client.
/// <note>
/// If you wish to upload an image and have it embedded in a <see cref="Discord.EmbedType.Rich"/> embed,
/// you may upload the file and refer to the file with "attachment://filename.ext" in the
/// <see cref="Discord.EmbedBuilder.ImageUrl"/>. See the example section for its usage.
/// </note>
/// </remarks>
/// <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="Discord.EmbedType.Rich"/> <see cref="Embed"/> to be sent.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents an asynchronous send operation for delivering the message. The task result
/// contains the sent message.
/// </returns>
Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null);
/// <summary> Gets a message from this message channel with the given id, or null if not found. </summary>
/// <summary>
/// Gets a message from this message channel.
/// </summary>
/// <param name="id">The snowflake identifier of the message.</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>
/// <returns>
/// A task that represents an asynchronous get operation for retrieving the message. The task result contains
/// the retrieved message; <c>null</c> if no message is found with the specified identifier.
/// </returns>
Task<IMessage> GetMessageAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the last N messages from this message channel. </summary>
/// <summary>
/// Gets the last N messages from this message channel.
/// </summary>
/// <remarks>
/// <note type="important">
/// The returned collection is an asynchronous enumerable object; one must call
/// <see cref="AsyncEnumerableExtensions.FlattenAsync{T}"/> to access the individual messages as a
/// collection.
/// </note>
/// <note type="warning">
/// Do not fetch too many messages at once! This may cause unwanted preemptive rate limit or even actual
/// rate limit, causing your bot to freeze!
/// </note>
/// This method will attempt to fetch the number of messages specified under <paramref name="limit"/>. The
/// library will attempt to split up the requests according to your <paramref name="limit"/> and
/// <see cref="DiscordConfig.MaxMessagesPerBatch"/>. In other words, should the user request 500 messages,
/// and the <see cref="Discord.DiscordConfig.MaxMessagesPerBatch"/> constant is <c>100</c>, the request will
/// be split into 5 individual requests; thus returning 5 individual asynchronous responses, hence the need
/// of flattening.
/// </remarks>
/// <example>
/// The following example downloads 300 messages and gets messages that belong to the user
/// <c>53905483156684800</c>.
/// <code lang="cs">
/// var messages = await messageChannel.GetMessagesAsync(300).FlattenAsync();
/// var userMessages = messages.Where(x =&gt; x.Author.Id == 53905483156684800);
/// </code>
/// </example>
/// <param name="limit">The numbers of message to be gotten from.</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>
/// <returns>
/// Paged collection of messages.
/// </returns>
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch,
CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a collection of messages in this channel. </summary>
/// <summary>
/// Gets a collection of messages in this channel.
/// </summary>
/// <remarks>
/// <note type="important">
/// The returned collection is an asynchronous enumerable object; one must call
/// <see cref="AsyncEnumerableExtensions.FlattenAsync{T}"/> to access the individual messages as a
/// collection.
/// </note>
/// <note type="warning">
/// Do not fetch too many messages at once! This may cause unwanted preemptive rate limit or even actual
/// rate limit, causing your bot to freeze!
/// </note>
/// This method will attempt to fetch the number of messages specified under <paramref name="limit"/> around
/// the message <paramref name="fromMessageId"/> depending on the <paramref name="dir"/>. The library will
/// attempt to split up the requests according to your <paramref name="limit"/> and
/// <see cref="DiscordConfig.MaxMessagesPerBatch"/>. In other words, should the user request 500 messages,
/// and the <see cref="Discord.DiscordConfig.MaxMessagesPerBatch"/> constant is <c>100</c>, the request will
/// be split into 5 individual requests; thus returning 5 individual asynchronous responses, hence the need
/// of flattening.
/// </remarks>
/// <example>
/// The following example gets 5 message prior to the message identifier <c>442012544660537354</c>.
/// <code lang="cs">
/// var messages = await channel.GetMessagesAsync(442012544660537354, Direction.Before, 5).FlattenAsync();
/// </code>
/// </example>
/// <param name="fromMessageId">The ID of the starting message to get the messages from.</param>
/// <param name="dir">The direction of the messages to be gotten from.</param>
/// <param name="limit">The numbers of message to be gotten from.</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>
/// <returns>
/// Paged collection of messages.
/// </returns>
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch,
CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a collection of messages in this channel. </summary>
/// <summary>
/// Gets a collection of messages in this channel.
/// </summary>
/// <remarks>
/// <note type="important">
/// The returned collection is an asynchronous enumerable object; one must call
/// <see cref="AsyncEnumerableExtensions.FlattenAsync{T}"/> to access the individual messages as a
/// collection.
/// </note>
/// <note type="warning">
/// Do not fetch too many messages at once! This may cause unwanted preemptive rate limit or even actual
/// rate limit, causing your bot to freeze!
/// </note>
/// This method will attempt to fetch the number of messages specified under <paramref name="limit"/> around
/// the message <paramref name="fromMessage"/> depending on the <paramref name="dir"/>. The library will
/// attempt to split up the requests according to your <paramref name="limit"/> and
/// <see cref="DiscordConfig.MaxMessagesPerBatch"/>. In other words, should the user request 500 messages,
/// and the <see cref="Discord.DiscordConfig.MaxMessagesPerBatch"/> constant is <c>100</c>, the request will
/// be split into 5 individual requests; thus returning 5 individual asynchronous responses, hence the need
/// of flattening.
/// </remarks>
/// <example>
/// The following example gets 5 message prior to a specific message, <c>oldMessage</c>.
/// <code lang="cs">
/// var messages = await channel.GetMessagesAsync(oldMessage, Direction.Before, 5).FlattenAsync();
/// </code>
/// </example>
/// <param name="fromMessage">The starting message to get the messages from.</param>
/// <param name="dir">The direction of the messages to be gotten from.</param>
/// <param name="limit">The numbers of message to be gotten from.</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>
/// <returns>
/// Paged collection of messages.
/// </returns>
IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch,
CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets a collection of pinned messages in this channel. </summary>
/// <summary>
/// Gets a collection of pinned messages in this channel.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation for retrieving pinned messages in this channel.
/// The task result contains a collection of messages found in the pinned messages.
/// </returns>
Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync(RequestOptions options = null);
/// <summary> Deletes a message based on the message ID in this channel. </summary>
/// <summary>
/// Deletes a message.
/// </summary>
/// <param name="messageId">The snowflake identifier of the message that would be removed.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous removal operation.
/// </returns>
Task DeleteMessageAsync(ulong messageId, RequestOptions options = null);
/// <summary> Deletes a message based on the provided message in this channel. </summary>
/// <param name="message">The message that would be removed.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous removal operation.
/// </returns>
Task DeleteMessageAsync(IMessage message, RequestOptions options = null);
/// <summary> Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds. </summary>
/// <summary>
/// Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous operation that triggers the broadcast.
/// </returns>
Task TriggerTypingAsync(RequestOptions options = null);
/// <summary> Continuously broadcasts the "user is typing" message to all users in this channel until the returned object is disposed. </summary>
/// <summary>
/// Continuously broadcasts the "user is typing" message to all users in this channel until the returned
/// object is disposed.
/// </summary>
/// <example>
/// The following example keeps the client in the typing state until <c>LongRunningAsync</c> has finished.
/// <code lang="cs">
/// using (messageChannel.EnterTypingState())
/// {
/// await LongRunningAsync();
/// }
/// </code>
/// </example>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A disposable object that, upon its disposal, will stop the client from broadcasting its typing state in
/// this channel.
/// </returns>
IDisposable EnterTypingState(RequestOptions options = null);
}
}

View File

@@ -3,14 +3,27 @@ using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// A type of guild channel that can be nested within a category.
/// Contains a CategoryId that is set to the parent category, if it is set.
/// Represents a type of guild channel that can be nested within a category.
/// </summary>
public interface INestedChannel : IGuildChannel
{
/// <summary> Gets the parentid (category) of this channel in the guild's channel list. </summary>
/// <summary>
/// Gets the parent (category) ID of this channel in the guild's channel list.
/// </summary>
/// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier of the parent of this channel;
/// <c>null</c> if none is set.
/// </returns>
ulong? CategoryId { get; }
/// <summary> Gets the parent channel (category) of this channel, if it is set. If unset, returns null.</summary>
/// <summary>
/// Gets the parent (category) channel of this channel.
/// </summary>
/// <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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the category channel
/// representing the parent of this channel; <c>null</c> if none is set.
/// </returns>
Task<ICategoryChannel> GetCategoryAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
}
}

View File

@@ -1,9 +1,18 @@
using System.Collections.Generic;
using System.Collections.Generic;
namespace Discord
{
/// <summary>
/// Represents a generic channel that is private to select recipients.
/// </summary>
public interface IPrivateChannel : IChannel
{
/// <summary>
/// Gets the users that can access this channel.
/// </summary>
/// <returns>
/// A read-only collection of users that can access this channel.
/// </returns>
IReadOnlyCollection<IUser> Recipients { get; }
}
}

View File

@@ -5,30 +5,114 @@ using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents a generic channel in a guild that can send and receive messages.
/// </summary>
public interface ITextChannel : IMessageChannel, IMentionable, INestedChannel
{
/// <summary> Checks if the channel is NSFW. </summary>
/// <summary>
/// Gets a value that indicates whether the channel is NSFW.
/// </summary>
/// <returns>
/// <c>true</c> if the channel has the NSFW flag enabled; otherwise <c>false</c>.
/// </returns>
bool IsNsfw { get; }
/// <summary> Gets the current topic for this text channel. </summary>
/// <summary>
/// Gets the current topic for this text channel.
/// </summary>
/// <returns>
/// A string representing the topic set in the channel; <c>null</c> if none is set.
/// </returns>
string Topic { get; }
///<summary> Gets the current slow-mode delay for this channel. 0 if disabled. </summary>
/// <summary>
/// Gets the current slow-mode delay for this channel.
/// </summary>
/// <returns>
/// An <see cref="Int32"/> representing the time in seconds required before the user can send another
/// message; <c>0</c> if disabled.
/// </returns>
int SlowModeInterval { get; }
/// <summary> Bulk deletes multiple messages. </summary>
/// <summary>
/// Bulk-deletes multiple messages.
/// </summary>
/// <example>
/// The following example gets 250 messages from the channel and deletes them.
/// <code lang="cs">
/// var messages = await textChannel.GetMessagesAsync(250).FlattenAsync();
/// await textChannel.DeleteMessagesAsync(messages);
/// </code>
/// </example>
/// <remarks>
/// This method attempts to remove the messages specified in bulk.
/// <note type="important">
/// Due to the limitation set by Discord, 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="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous bulk-removal operation.
/// </returns>
Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null);
/// <summary> Bulk deletes multiple messages. </summary>
/// <summary>
/// Bulk-deletes multiple messages.
/// </summary>
/// <remarks>
/// This method attempts to remove the messages specified in bulk.
/// <note type="important">
/// Due to the limitation set by Discord, this method can only remove messages that are posted within 14 days!
/// </note>
/// </remarks>
/// <param name="messageIds">The snowflake identifier of the messages to be bulk-deleted.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous bulk-removal operation.
/// </returns>
Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null);
/// <summary> Modifies this text channel. </summary>
/// <summary>
/// Modifies this text channel.
/// </summary>
/// <param name="func">The delegate containing the properties to modify the channel with.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous modification operation.
/// </returns>
/// <seealso cref="TextChannelProperties"/>
Task ModifyAsync(Action<TextChannelProperties> func, RequestOptions options = null);
/// <summary> Creates a webhook in this text channel. </summary>
/// <summary>
/// Creates a webhook in this text channel.
/// </summary>
/// <param name="name">The name of the webhook.</param>
/// <param name="avatar">The avatar of the webhook.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous creation operation. The task result contains the newly created
/// webhook.
/// </returns>
Task<IWebhook> CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null);
/// <summary> Gets the webhook in this text channel with the provided id, or null if not found. </summary>
/// <summary>
/// Gets a webhook available in this text channel.
/// </summary>
/// <param name="id">The identifier of the webhook.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a webhook associated
/// with the identifier; <c>null</c> if the webhook is not found.
/// </returns>
Task<IWebhook> GetWebhookAsync(ulong id, RequestOptions options = null);
/// <summary> Gets the webhooks for this text channel. </summary>
/// <summary>
/// Gets the webhooks available in this text channel.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection
/// of webhooks that is available in this channel.
/// </returns>
Task<IReadOnlyCollection<IWebhook>> GetWebhooksAsync(RequestOptions options = null);
}
}

View File

@@ -3,14 +3,37 @@ using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents a generic voice channel in a guild.
/// </summary>
public interface IVoiceChannel : INestedChannel, IAudioChannel
{
/// <summary> Gets the bitrate, in bits per second, clients in this voice channel are requested to use. </summary>
/// <summary>
/// Gets the bit-rate that the clients in this voice channel are requested to use.
/// </summary>
/// <returns>
/// An <see cref="int"/> representing the bit-rate (bps) that this voice channel defines and requests the
/// client(s) to use.
/// </returns>
int Bitrate { get; }
/// <summary> Gets the max amount of users allowed to be connected to this channel at one time. </summary>
/// <summary>
/// Gets the max number of users allowed to be connected to this channel at once.
/// </summary>
/// <returns>
/// An <see cref="int"/> representing the maximum number of users that are allowed to be connected to this
/// channel at once; <c>null</c> if a limit is not set.
/// </returns>
int? UserLimit { get; }
/// <summary> Modifies this voice channel. </summary>
/// <summary>
/// Modifies this voice channel.
/// </summary>
/// <param name="func">The properties to modify the channel with.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous modification operation.
/// </returns>
/// <seealso cref="VoiceChannelProperties"/>
Task ModifyAsync(Action<VoiceChannelProperties> func, RequestOptions options = null);
}
}

View File

@@ -1,12 +1,28 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Provides properties that are used to reorder an <see cref="IGuildChannel"/>.
/// </summary>
public class ReorderChannelProperties
{
/// <summary>The id of the channel to apply this position to.</summary>
/// <summary>
/// Gets the ID of the channel to apply this position to.
/// </summary>
/// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier of this channel.
/// </returns>
public ulong Id { get; }
/// <summary>The new zero-based position of this channel. </summary>
/// <summary>
/// Gets the new zero-based position of this channel.
/// </summary>
/// <returns>
/// An <see cref="int"/> representing the new position of this channel.
/// </returns>
public int Position { get; }
/// <summary> Initializes a new instance of the <see cref="ReorderChannelProperties"/> class used to reorder a channel. </summary>
/// <param name="id"> Sets the ID of the channel to apply this position to. </param>
/// <param name="position"> Sets the new zero-based position of this channel. </param>
public ReorderChannelProperties(ulong id, int position)
{
Id = id;

View File

@@ -1,27 +1,29 @@
using System;
namespace Discord
{
/// <inheritdoc />
/// <summary>
/// Provides properties that are used to modify an <see cref="ITextChannel"/> with the specified changes.
/// </summary>
/// <seealso cref="ITextChannel.ModifyAsync(System.Action{TextChannelProperties}, RequestOptions)"/>
public class TextChannelProperties : GuildChannelProperties
{
/// <summary>
/// What the topic of the channel should be set to.
/// Gets or sets the topic of the channel.
/// </summary>
public Optional<string> Topic { get; set; }
/// <summary>
/// Should this channel be flagged as NSFW?
/// Gets or sets whether this channel should be flagged as NSFW.
/// </summary>
public Optional<bool> IsNsfw { get; set; }
/// <summary>
/// What the slow-mode ratelimit for this channel should be set to; 0 will disable slow-mode.
/// Gets or sets the slow-mode ratelimit in seconds for this channel.
/// </summary>
/// <remarks>
/// This value must fall within [0, 120]
///
/// Users with <see cref="ChannelPermission.ManageMessages"/> will be exempt from slow-mode.
/// Setting this value to <c>0</c> will disable slow-mode for this channel.
/// <note>
/// Users with <see cref="Discord.ChannelPermission.ManageMessages" /> will be exempt from slow-mode.
/// </note>
/// </remarks>
/// <exception cref="ArgumentOutOfRangeException">Throws ArgummentOutOfRange if the value does not fall within [0, 120]</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown if the value does not fall within [0, 120].</exception>
public Optional<int> SlowModeInterval { get; set; }
}
}

View File

@@ -1,14 +1,16 @@
namespace Discord
namespace Discord
{
/// <inheritdoc />
/// <summary>
/// Provides properties that are used to modify an <see cref="IVoiceChannel" /> with the specified changes.
/// </summary>
public class VoiceChannelProperties : GuildChannelProperties
{
/// <summary>
/// The bitrate of the voice connections in this channel. Must be greater than 8000
/// Gets or sets the bitrate of the voice connections in this channel. Must be greater than 8000.
/// </summary>
public Optional<int> Bitrate { get; set; }
/// <summary>
/// The maximum number of users that can be present in a channel.
/// Gets or sets the maximum number of users that can be present in a channel, or <c>null</c> if none.
/// </summary>
public Optional<int?> UserLimit { get; set; }
}

View File

@@ -1,28 +1,35 @@
namespace Discord
namespace Discord
{
/// <summary>
/// A unicode emoji
/// A Unicode emoji.
/// </summary>
public class Emoji : IEmote
{
// TODO: need to constrain this to unicode-only emojis somehow
// TODO: need to constrain this to Unicode-only emojis somehow
/// <summary>
/// The unicode representation of this emote.
/// </summary>
/// <inheritdoc />
public string Name { get; }
/// <summary>
/// Gets the Unicode representation of this emote.
/// </summary>
/// <returns>
/// A string that resolves to <see cref="Emoji.Name"/>.
/// </returns>
public override string ToString() => Name;
/// <summary>
/// Creates a unicode emoji.
/// Initializes a new <see cref="Emoji"/> class with the provided Unicode.
/// </summary>
/// <param name="unicode">The pure UTF-8 encoding of an emoji</param>
/// <param name="unicode">The pure UTF-8 encoding of an emoji.</param>
public Emoji(string unicode)
{
Name = unicode;
}
/// <summary>
/// Determines whether the specified emoji is equal to the current one.
/// </summary>
/// <param name="other">The object to compare with the current object.</param>
public override bool Equals(object other)
{
if (other == null) return false;
@@ -34,6 +41,7 @@
return string.Equals(Name, otherEmoji.Name);
}
/// <inheritdoc />
public override int GetHashCode() => Name.GetHashCode();
}
}

View File

@@ -1,26 +1,34 @@
using System;
using System.Globalization;
using System.Diagnostics;
namespace Discord
{
/// <summary>
/// A custom image-based emote
/// A custom image-based emote.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class Emote : IEmote, ISnowflakeEntity
{
/// <summary>
/// The display name (tooltip) of this emote
/// </summary>
/// <inheritdoc />
public string Name { get; }
/// <summary>
/// The ID of this emote
/// </summary>
/// <inheritdoc />
public ulong Id { get; }
/// <summary>
/// Is this emote animated?
/// Gets whether this emote is animated.
/// </summary>
/// <returns>
/// A boolean that determines whether or not this emote is an animated one.
/// </returns>
public bool Animated { get; }
/// <inheritdoc />
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);
/// <summary>
/// Gets the image URL of this emote.
/// </summary>
/// <returns>
/// A string that points to the URL of this emote.
/// </returns>
public string Url => CDN.GetEmojiUrl(Id, Animated);
internal Emote(ulong id, string name, bool animated)
@@ -30,6 +38,10 @@ namespace Discord
Animated = animated;
}
/// <summary>
/// Determines whether the specified emote is equal to the current emote.
/// </summary>
/// <param name="other">The object to compare with the current object.</param>
public override bool Equals(object other)
{
if (other == null) return false;
@@ -41,6 +53,7 @@ namespace Discord
return string.Equals(Name, otherEmote.Name) && Id == otherEmote.Id;
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
@@ -49,18 +62,20 @@ namespace Discord
}
}
/// <summary>
/// Parse an Emote from its raw format
/// </summary>
/// <param name="text">The raw encoding of an emote; for example, &lt;:dab:277855270321782784&gt;</param>
/// <returns>An emote</returns>
/// <summary> Parses an <see cref="Emote"/> from its raw format. </summary>
/// <param name="text">The raw encoding of an emote (e.g. <c>&lt;:dab:277855270321782784&gt;</c>).</param>
/// <returns>An emote.</returns>
/// <exception cref="ArgumentException">Invalid emote format.</exception>
public static Emote Parse(string text)
{
if (TryParse(text, out Emote result))
return result;
throw new ArgumentException(message: "Invalid emote format", paramName: nameof(text));
throw new ArgumentException(message: "Invalid emote format.", paramName: nameof(text));
}
/// <summary> Tries to parse an <see cref="Emote"/> from its raw format. </summary>
/// <param name="text">The raw encoding of an emote; for example, &lt;:dab:277855270321782784&gt;.</param>
/// <param name="result">An emote.</param>
public static bool TryParse(string text, out Emote result)
{
result = null;
@@ -85,6 +100,12 @@ namespace Discord
}
private string DebuggerDisplay => $"{Name} ({Id})";
/// <summary>
/// Returns the raw representation of the emote.
/// </summary>
/// <returns>
/// A string representing the raw presentation of the emote (e.g. <c>&lt;:thonkang:282745590985523200&gt;</c>).
/// </returns>
public override string ToString() => $"<{(Animated ? "a" : "")}:{Name}:{Id}>";
}
}

View File

@@ -1,10 +1,20 @@
using System.Collections.Generic;
using System.Collections.Generic;
namespace Discord
{
/// <summary>
/// Provides properties that are used to modify an <see cref="Emote" /> with the specified changes.
/// </summary>
/// <seealso cref="IGuild.ModifyEmoteAsync"/>
public class EmoteProperties
{
/// <summary>
/// Gets or sets the name of the <see cref="Emote"/>.
/// </summary>
public Optional<string> Name { get; set; }
/// <summary>
/// Gets or sets the roles that can access this <see cref="Emote"/>.
/// </summary>
public Optional<IEnumerable<IRole>> Roles { get; set; }
}
}

View File

@@ -1,16 +1,34 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Diagnostics;
namespace Discord
{
/// <summary>
/// An image-based emote that is attached to a guild
/// An image-based emote that is attached to a guild.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class GuildEmote : Emote
{
/// <summary>
/// Gets whether this emoji is managed by an integration.
/// </summary>
/// <returns>
/// A boolean that determines whether or not this emote is managed by a Twitch integration.
/// </returns>
public bool IsManaged { get; }
/// <summary>
/// Gets whether this emoji must be wrapped in colons.
/// </summary>
/// <returns>
/// A boolean that determines whether or not this emote requires the use of colons in chat to be used.
/// </returns>
public bool RequireColons { get; }
/// <summary>
/// Gets the roles that are allowed to use this emoji.
/// </summary>
/// <returns>
/// A read-only list containing snowflake identifiers for roles that are allowed to use this emoji.
/// </returns>
public IReadOnlyList<ulong> RoleIds { get; }
internal GuildEmote(ulong id, string name, bool animated, bool isManaged, bool requireColons, IReadOnlyList<ulong> roleIds) : base(id, name, animated)
@@ -21,6 +39,12 @@ namespace Discord
}
private string DebuggerDisplay => $"{Name} ({Id})";
/// <summary>
/// Gets the raw representation of the emote.
/// </summary>
/// <returns>
/// A string representing the raw presentation of the emote (e.g. <c>&lt;:thonkang:282745590985523200&gt;</c>).
/// </returns>
public override string ToString() => $"<{(Animated ? "a" : "")}:{Name}:{Id}>";
}
}

View File

@@ -1,13 +1,16 @@
namespace Discord
namespace Discord
{
/// <summary>
/// A general container for any type of emote in a message.
/// Represents a general container for any type of emote in a message.
/// </summary>
public interface IEmote
{
/// <summary>
/// The display name or unicode representation of this emote
/// Gets the display name or Unicode representation of this emote.
/// </summary>
/// <returns>
/// A string representing the display name or the Unicode representation (e.g. <c>🤔</c>) of this emote.
/// </returns>
string Name { get; }
}
}

View File

@@ -1,10 +1,17 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Specifies the default message notification behavior the guild uses.
/// </summary>
public enum DefaultMessageNotifications
{
/// <summary> By default, all messages will trigger notifications. </summary>
/// <summary>
/// By default, all messages will trigger notifications.
/// </summary>
AllMessages = 0,
/// <summary> By default, only mentions will trigger notifications. </summary>
/// <summary>
/// By default, only mentions will trigger notifications.
/// </summary>
MentionsOnly = 1
}
}

View File

@@ -1,20 +1,20 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Modify the widget of an IGuild with the specified parameters
/// Provides properties that are used to modify the widget of an <see cref="IGuild" /> with the specified changes.
/// </summary>
public class GuildEmbedProperties
{
/// <summary>
/// Should the widget be enabled?
/// Sets whether the widget should be enabled.
/// </summary>
public Optional<bool> Enabled { get; set; }
/// <summary>
/// What channel should the invite place users in, if not null.
/// Sets the channel that the invite should place its users in, if not <c>null</c>.
/// </summary>
public Optional<IChannel> Channel { get; set; }
/// <summary>
/// What channel should the invite place users in, if not null.
/// Sets the channel the invite should place its users in, if not <c>null</c>.
/// </summary>
public Optional<ulong?> ChannelId { get; set; }
}

View File

@@ -1,9 +1,21 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Provides properties used to modify an <see cref="IGuildIntegration" /> with the specified changes.
/// </summary>
public class GuildIntegrationProperties
{
/// <summary>
/// Gets or sets the behavior when an integration subscription lapses.
/// </summary>
public Optional<int> ExpireBehavior { get; set; }
/// <summary>
/// Gets or sets the period (in seconds) where the integration will ignore lapsed subscriptions.
/// </summary>
public Optional<int> ExpireGracePeriod { get; set; }
/// <summary>
/// Gets or sets whether emoticons should be synced for this integration.
/// </summary>
public Optional<bool> EnableEmoticons { get; set; }
}
}

View File

@@ -1,78 +1,69 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Modify an IGuild with the specified changes
/// Provides properties that are used to modify an <see cref="IGuild" /> with the specified changes.
/// </summary>
/// <example>
/// <code language="c#">
/// await Context.Guild.ModifyAsync(async x =>
/// {
/// x.Name = "aaaaaah";
/// x.RegionId = (await Context.Client.GetOptimalVoiceRegionAsync()).Id;
/// });
/// </code>
/// </example>
/// <see cref="IGuild"/>
/// <see cref="IGuild.ModifyAsync"/>
public class GuildProperties
{
public Optional<string> Username { get; set; }
/// <summary>
/// The name of the Guild
/// Gets or sets the name of the guild. Must be within 100 characters.
/// </summary>
public Optional<string> Name { get; set; }
/// <summary>
/// The region for the Guild's voice connections
/// Gets or sets the region for the guild's voice connections.
/// </summary>
public Optional<IVoiceRegion> Region { get; set; }
/// <summary>
/// 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>
public Optional<string> RegionId { get; set; }
/// <summary>
/// What verification level new users need to achieve before speaking
/// Gets or sets the verification level new users need to achieve before speaking.
/// </summary>
public Optional<VerificationLevel> VerificationLevel { get; set; }
/// <summary>
/// The default message notification state for the guild
/// Gets or sets the default message notification state for the guild.
/// </summary>
public Optional<DefaultMessageNotifications> DefaultMessageNotifications { get; set; }
/// <summary>
/// How many seconds before a user is sent to AFK. This value MUST be one of: (60, 300, 900, 1800, 3600).
/// Gets or sets how many seconds before a user is sent to AFK. This value MUST be one of: (60, 300, 900,
/// 1800, 3600).
/// </summary>
public Optional<int> AfkTimeout { get; set; }
/// <summary>
/// The icon of the guild
/// Gets or sets the icon of the guild.
/// </summary>
public Optional<Image?> Icon { get; set; }
/// <summary>
/// The guild's splash image
/// Gets or sets the guild's splash image.
/// </summary>
/// <remarks>
/// The guild must be partnered for this value to have any effect.
/// The guild must be partnered for this value to have any effect.
/// </remarks>
public Optional<Image?> Splash { get; set; }
/// <summary>
/// The IVoiceChannel where AFK users should be sent.
/// Gets or sets the <see cref="IVoiceChannel"/> where AFK users should be sent.
/// </summary>
public Optional<IVoiceChannel> AfkChannel { get; set; }
/// <summary>
/// The ID of the IVoiceChannel where AFK users should be sent.
/// Gets or sets the ID of the <see cref="IVoiceChannel"/> where AFK users should be sent.
/// </summary>
public Optional<ulong?> AfkChannelId { get; set; }
/// <summary>
/// The ITextChannel where System messages should be sent.
/// Gets or sets the <see cref="ITextChannel" /> where system messages should be sent.
/// </summary>
public Optional<ITextChannel> SystemChannel { get; set; }
/// <summary>
/// The ID of the ITextChannel where System messages should be sent.
/// Gets or sets the ID of the <see cref="ITextChannel" /> where system messages should be sent.
/// </summary>
public Optional<ulong?> SystemChannelId { get; set; }
/// <summary>
/// The owner of this guild.
/// Gets or sets the owner of this guild.
/// </summary>
public Optional<IUser> Owner { get; set; }
/// <summary>
/// The ID of the owner of this guild.
/// Gets or sets the ID of the owner of this guild.
/// </summary>
public Optional<ulong> OwnerId { get; set; }
}

View File

@@ -1,8 +1,23 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Represents a generic ban object.
/// </summary>
public interface IBan
{
/// <summary>
/// Gets the banned user.
/// </summary>
/// <returns>
/// A user that was banned.
/// </returns>
IUser User { get; }
/// <summary>
/// Gets the reason why the user is banned if specified.
/// </summary>
/// <returns>
/// A string containing the reason behind the ban; <c>null</c> if none is specified.
/// </returns>
string Reason { get; }
}
}

View File

@@ -5,165 +5,668 @@ using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents a generic guild/server.
/// </summary>
public interface IGuild : IDeletable, ISnowflakeEntity
{
/// <summary> Gets the name of this guild. </summary>
/// <summary>
/// Gets the name of this guild.
/// </summary>
/// <returns>
/// A string containing the name of this guild.
/// </returns>
string Name { get; }
/// <summary> 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. </summary>
/// <summary>
/// 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.
/// </summary>
/// <returns>
/// An <see cref="int"/> representing 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; }
/// <summary> Returns true if this guild is embeddable (e.g. widget) </summary>
/// <summary>
/// Gets a value that indicates whether this guild is embeddable (i.e. can use widget).
/// </summary>
/// <returns>
/// <c>true</c> if this guild can be embedded via widgets; otherwise <c>false</c>.
/// </returns>
bool IsEmbeddable { get; }
/// <summary> Gets the default message notifications for users who haven't explicitly set their notification settings. </summary>
/// <summary>
/// Gets the default message notifications for users who haven't explicitly set their notification settings.
/// </summary>
DefaultMessageNotifications DefaultMessageNotifications { get; }
/// <summary> Gets the level of mfa requirements a user must fulfill before being allowed to perform administrative actions in this guild. </summary>
/// <summary>
/// Gets the level of Multi-Factor Authentication requirements a user must fulfill before being allowed to
/// perform administrative actions in this guild.
/// </summary>
/// <returns>
/// The level of MFA requirement.
/// </returns>
MfaLevel MfaLevel { get; }
/// <summary> Gets the level of requirements a user must fulfill before being allowed to post messages in this guild. </summary>
/// <summary>
/// Gets the level of requirements a user must fulfill before being allowed to post messages in this guild.
/// </summary>
/// <returns>
/// The level of requirements.
/// </returns>
VerificationLevel VerificationLevel { get; }
/// <summary> Returns the id of this guild's icon, or null if one is not set. </summary>
/// <summary>
/// Gets the ID of this guild's icon.
/// </summary>
/// <returns>
/// An identifier for the splash image; <c>null</c> if none is set.
/// </returns>
string IconId { get; }
/// <summary> Returns the url to this guild's icon, or null if one is not set. </summary>
/// <summary>
/// Gets the URL of this guild's icon.
/// </summary>
/// <returns>
/// A URL pointing to the guild's icon; <c>null</c> if none is set.
/// </returns>
string IconUrl { get; }
/// <summary> Returns the id of this guild's splash image, or null if one is not set. </summary>
/// <summary>
/// Gets the ID of this guild's splash image.
/// </summary>
/// <returns>
/// An identifier for the splash image; <c>null</c> if none is set.
/// </returns>
string SplashId { get; }
/// <summary> Returns the url to this guild's splash image, or null if one is not set. </summary>
/// <summary>
/// Gets the URL of this guild's splash image.
/// </summary>
/// <returns>
/// A URL pointing to the guild's splash image; <c>null</c> if none is set.
/// </returns>
string SplashUrl { get; }
/// <summary> Returns true if this guild is currently connected and ready to be used. Only applies to the WebSocket client. </summary>
/// <summary>
/// Determines if this guild is currently connected and ready to be used.
/// </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>
/// <c>true</c> if this guild is currently connected and ready to be used; otherwise <c>false</c>.
/// </returns>
bool Available { get; }
/// <summary> Gets the id of the AFK voice channel for this guild if set, or null if not. </summary>
/// <summary>
/// Gets the ID of the AFK voice channel for this guild.
/// </summary>
/// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier of the AFK voice channel; <c>null</c> if
/// none is set.
/// </returns>
ulong? AFKChannelId { get; }
/// <summary> Gets the id of the the default channel for this guild. </summary>
/// <summary>
/// Gets the ID of the default channel for this guild.
/// </summary>
/// <remarks>
/// This property retrieves the snowflake identifier of the first viewable text channel for this guild.
/// <note type="warning">
/// This channel does not guarantee the user can send message to it, as it only looks for the first viewable
/// text channel.
/// </note>
/// </remarks>
/// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier of the default text channel; <c>0</c> if
/// none can be found.
/// </returns>
ulong DefaultChannelId { get; }
/// <summary> Gets the id of the embed channel for this guild if set, or null if not. </summary>
/// <summary>
/// Gets the ID of the widget embed channel of this guild.
/// </summary>
/// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier of the embedded channel found within the
/// widget settings of this guild; <c>null</c> if none is set.
/// </returns>
ulong? EmbedChannelId { get; }
/// <summary> Gets the id of the channel where randomized welcome messages are sent, or null if not. </summary>
/// <summary>
/// Gets the ID of the channel where randomized welcome messages are sent.
/// </summary>
/// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier of the system channel where randomized
/// welcome messages are sent; <c>null</c> if none is set.
/// </returns>
ulong? SystemChannelId { get; }
/// <summary> Gets the id of the user that created this guild. </summary>
/// <summary>
/// Gets the ID of the user that owns this guild.
/// </summary>
/// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier of the user that owns this guild.
/// </returns>
ulong OwnerId { get; }
/// <summary> Gets the id of the region hosting this guild's voice channels. </summary>
/// <summary>
/// Gets the ID of the region hosting this guild's voice channels.
/// </summary>
/// <returns>
/// A string containing the identifier for the voice region that this guild uses (e.g. <c>eu-central</c>).
/// </returns>
string VoiceRegionId { get; }
/// <summary> Gets the IAudioClient currently associated with this guild. </summary>
/// <summary>
/// Gets the <see cref="IAudioClient"/> currently associated with this guild.
/// </summary>
/// <returns>
/// An <see cref="IAudioClient"/> currently associated with this guild.
/// </returns>
IAudioClient AudioClient { get; }
/// <summary> Gets the built-in role containing all users in this guild. </summary>
/// <summary>
/// Gets the built-in role containing all users in this guild.
/// </summary>
/// <returns>
/// A role object that represents an <c>@everyone</c> role in this guild.
/// </returns>
IRole EveryoneRole { get; }
/// <summary> Gets a collection of all custom emojis for this guild. </summary>
/// <summary>
/// Gets a collection of all custom emotes for this guild.
/// </summary>
/// <returns>
/// A read-only collection of all custom emotes for this guild.
/// </returns>
IReadOnlyCollection<GuildEmote> Emotes { get; }
/// <summary> Gets a collection of all extra features added to this guild. </summary>
/// <summary>
/// Gets a collection of all extra features added to this guild.
/// </summary>
/// <returns>
/// A read-only collection of enabled features in this guild.
/// </returns>
IReadOnlyCollection<string> Features { get; }
/// <summary> Gets a collection of all roles in this guild. </summary>
/// <summary>
/// Gets a collection of all roles in this guild.
/// </summary>
/// <returns>
/// A read-only collection of roles found within this guild.
/// </returns>
IReadOnlyCollection<IRole> Roles { get; }
/// <summary> Modifies this guild. </summary>
/// <summary>
/// Modifies this guild.
/// </summary>
/// <param name="func">The delegate containing the properties to modify the guild with.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous modification operation.
/// </returns>
Task ModifyAsync(Action<GuildProperties> func, RequestOptions options = null);
/// <summary> Modifies this guild's embed. </summary>
/// <summary>
/// Modifies this guild's embed channel.
/// </summary>
/// <param name="func">The delegate containing the properties to modify the guild widget with.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous modification operation.
/// </returns>
Task ModifyEmbedAsync(Action<GuildEmbedProperties> func, RequestOptions options = null);
/// <summary> Bulk modifies the channels of this guild. </summary>
/// <summary>
/// Bulk-modifies the order of channels in this guild.
/// </summary>
/// <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>
/// <returns>
/// A task that represents the asynchronous reorder operation.
/// </returns>
Task ReorderChannelsAsync(IEnumerable<ReorderChannelProperties> args, RequestOptions options = null);
/// <summary> Bulk modifies the roles of this guild. </summary>
/// <summary>
/// Bulk-modifies the order of roles in this guild.
/// </summary>
/// <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>
/// <returns>
/// A task that represents the asynchronous reorder operation.
/// </returns>
Task ReorderRolesAsync(IEnumerable<ReorderRoleProperties> args, RequestOptions options = null);
/// <summary> Leaves this guild. If you are the owner, use Delete instead. </summary>
/// <summary>
/// Leaves this guild.
/// </summary>
/// <remarks>
/// This method will make the currently logged-in user leave the guild.
/// <note>
/// If the user is the owner of this guild, use <see cref="IDeletable.DeleteAsync"/> instead.
/// </note>
/// </remarks>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous leave operation.
/// </returns>
Task LeaveAsync(RequestOptions options = null);
/// <summary> Gets a collection of all users banned on this guild. </summary>
/// <summary>
/// Gets a collection of all users banned in this guild.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection of
/// ban objects that this guild currently possesses, with each object containing the user banned and reason
/// behind the ban.
/// </returns>
Task<IReadOnlyCollection<IBan>> GetBansAsync(RequestOptions options = null);
/// <summary>
/// Gets a ban object for a banned user.
/// </summary>
/// <param name="user">The banned user.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// An awaitable <see cref="Task"/> containing the ban object, which contains the user information and the
/// reason for the ban; <see langword="null"/> if the ban entry cannot be found.
/// A task that represents the asynchronous get operation. The task result contains a 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>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// An awaitable <see cref="Task"/> containing the ban object, which contains the user information and the
/// reason for the ban; <see langword="null"/> if the ban entry cannot be found.
/// A task that represents the asynchronous get operation. The task result contains a 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 provided user from this guild and optionally prunes their recent messages. </summary>
/// <param name="pruneDays">The number of days to remove messages from this user for - must be between [0, 7]</param>
/// <summary>
/// Bans the user from this 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, and this number must be between [0, 7].</param>
/// <param name="reason">The reason of the ban to be written in the audit log.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <exception cref="ArgumentException"><paramref name="pruneDays"/> is not between 0 to 7.</exception>
/// <returns>
/// A task that represents the asynchronous add operation for the ban.
/// </returns>
Task AddBanAsync(IUser user, int pruneDays = 0, string reason = null, RequestOptions options = null);
/// <summary> Bans the provided user id from this guild and optionally prunes their recent messages. </summary>
/// <param name="pruneDays">The number of days to remove messages from this user for - must be between [0, 7]</param>
/// <summary>
/// Bans the user from this guild and optionally prunes their recent messages.
/// </summary>
/// <param name="userId">The snowflake ID of the user to ban.</param>
/// <param name="pruneDays">The number of days to remove messages from this user for, and this number must be between [0, 7].</param>
/// <param name="reason">The reason of the ban to be written in the audit log.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <exception cref="ArgumentException"><paramref name="pruneDays"/> is not between 0 to 7.</exception>
/// <returns>
/// A task that represents the asynchronous add operation for the ban.
/// </returns>
Task AddBanAsync(ulong userId, int pruneDays = 0, string reason = null, RequestOptions options = null);
/// <summary> Unbans the provided user if it is currently banned. </summary>
/// <summary>
/// Unbans the user if they are currently banned.
/// </summary>
/// <param name="user">The user to be unbanned.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous removal operation for the ban.
/// </returns>
Task RemoveBanAsync(IUser user, RequestOptions options = null);
/// <summary> Unbans the provided user id if it is currently banned. </summary>
/// <summary>
/// Unbans the user if they are currently banned.
/// </summary>
/// <param name="userId">The snowflake identifier of the user to be unbanned.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous removal operation for the ban.
/// </returns>
Task RemoveBanAsync(ulong userId, RequestOptions options = null);
/// <summary> Gets a collection of all channels in this guild. </summary>
/// <summary>
/// Gets a collection of all channels in this guild.
/// </summary>
/// <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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection of
/// generic channels found within this guild.
/// </returns>
Task<IReadOnlyCollection<IGuildChannel>> GetChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the channel in this guild with the provided id, or null if not found. </summary>
/// <summary>
/// Gets a channel in this guild.
/// </summary>
/// <param name="id">The snowflake identifier for the channel.</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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the generic channel
/// associated with the specified <paramref name="id"/>; <c>null</c> if none is found.
/// </returns>
Task<IGuildChannel> GetChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary>
/// Gets a collection of all text channels in this guild.
/// </summary>
/// <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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection of
/// message channels found within this guild.
/// </returns>
Task<IReadOnlyCollection<ITextChannel>> GetTextChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary>
/// Gets a text channel in this guild.
/// </summary>
/// <param name="id">The snowflake identifier for the text channel.</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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the text channel
/// associated with the specified <paramref name="id"/>; <c>null</c> if none is found.
/// </returns>
Task<ITextChannel> GetTextChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary>
/// Gets a collection of all voice channels in this guild.
/// </summary>
/// <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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection of
/// voice channels found within this guild.
/// </returns>
Task<IReadOnlyCollection<IVoiceChannel>> GetVoiceChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary>
/// Gets a collection of all category channels in this guild.
/// </summary>
/// <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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection of
/// category channels found within this guild.
/// </returns>
Task<IReadOnlyCollection<ICategoryChannel>> GetCategoriesAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary>
/// Gets a voice channel in this guild.
/// </summary>
/// <param name="id">The snowflake identifier for the voice channel.</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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the voice channel associated
/// with the specified <paramref name="id"/>; <c>null</c> if none is found.
/// </returns>
Task<IVoiceChannel> GetVoiceChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary>
/// Gets the AFK voice channel in this guild.
/// </summary>
/// <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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the voice channel that the
/// AFK users will be moved to after they have idled for too long; <c>null</c> if none is set.
/// </returns>
Task<IVoiceChannel> GetAFKChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary>
/// Gets the system channel where randomized welcome messages are sent in this guild.
/// </summary>
/// <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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the text channel where
/// randomized welcome messages will be sent to; <c>null</c> if none is set.
/// </returns>
Task<ITextChannel> GetSystemChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary>
/// Gets the first viewable text channel in this guild.
/// </summary>
/// <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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the first viewable text
/// channel in this guild; <c>null</c> if none is found.
/// </returns>
Task<ITextChannel> GetDefaultChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary>
/// Gets the embed channel (i.e. the channel set in the guild's widget settings) in this guild.
/// </summary>
/// <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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the embed channel set
/// within the server's widget settings; <c>null</c> if none is set.
/// </returns>
Task<IGuildChannel> GetEmbedChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Creates a new text channel. </summary>
/// <summary>
/// Creates a new text channel in this guild.
/// </summary>
/// <example>
/// The following example creates a new text channel under an existing category named <c>Wumpus</c> with a set topic.
/// <code lang="cs">
/// var categories = await guild.GetCategoriesAsync();
/// var targetCategory = categories.FirstOrDefault(x => x.Name == "wumpus");
/// if (targetCategory == null) return;
/// await Context.Guild.CreateTextChannelAsync(name, x =>
/// {
/// x.CategoryId = targetCategory.Id;
/// x.Topic = $"This channel was created at {DateTimeOffset.UtcNow} by {user}.";
/// });
/// </code>
/// </example>
/// <param name="name">The new name for the text channel.</param>
/// <param name="func">The delegate containing the properties to be applied to the channel upon its creation.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous creation operation. The task result contains the newly created
/// text channel.
/// </returns>
Task<ITextChannel> CreateTextChannelAsync(string name, Action<TextChannelProperties> func = null, RequestOptions options = null);
/// <summary> Creates a new voice channel. </summary>
/// <summary>
/// Creates a new voice channel in this guild.
/// </summary>
/// <param name="name">The new name for the voice channel.</param>
/// <param name="func">The delegate containing the properties to be applied to the channel upon its creation.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous creation operation. The task result contains the newly created
/// voice channel.
/// </returns>
Task<IVoiceChannel> CreateVoiceChannelAsync(string name, Action<VoiceChannelProperties> func = null, RequestOptions options = null);
/// <summary> Creates a new channel category. </summary>
/// <summary>
/// Creates a new channel category in this guild.
/// </summary>
/// <param name="name">The new name for the category.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous creation operation. The task result contains the newly created
/// category channel.
/// </returns>
Task<ICategoryChannel> CreateCategoryAsync(string name, RequestOptions options = null);
Task<IReadOnlyCollection<IGuildIntegration>> GetIntegrationsAsync(RequestOptions options = null);
Task<IGuildIntegration> CreateIntegrationAsync(ulong id, string type, RequestOptions options = null);
/// <summary> Gets a collection of all invites to this guild. </summary>
/// <summary>
/// Gets a collection of all invites in this guild.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection of
/// invite metadata, each representing information for an invite found within this guild.
/// </returns>
Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null);
/// <summary>
/// Gets the vanity invite URL of this guild.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// An awaitable <see cref="Task"/> containing the partial metadata of the vanity invite found within
/// this guild.
/// A task that represents the asynchronous get operation. The task result contains the partial metadata of
/// the vanity invite found within this guild; <c>null</c> if none is found.
/// </returns>
Task<IInviteMetadata> GetVanityInviteAsync(RequestOptions options = null);
/// <summary> Gets the role in this guild with the provided id, or null if not found. </summary>
/// <summary>
/// Gets a role in this guild.
/// </summary>
/// <param name="id">The snowflake identifier for the role.</param>
/// <returns>
/// A role that is associated with the specified <paramref name="id"/>; <c>null</c> if none is found.
/// </returns>
IRole GetRole(ulong id);
/// <summary> Creates a new role. </summary>
/// <summary>
/// Creates a new role with the provided name.
/// </summary>
/// <param name="name">The new name for the role.</param>
/// <param name="permissions">The guild permission that the role should possess.</param>
/// <param name="color">The color of the role.</param>
/// <param name="isHoisted">Whether the role is separated from others on the sidebar.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous creation operation. The task result contains the newly created
/// role.
/// </returns>
Task<IRole> CreateRoleAsync(string name, GuildPermissions? permissions = null, Color? color = null, bool isHoisted = false, RequestOptions options = null);
/// <summary> Gets a collection of all users in this guild. </summary>
Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); //TODO: shouldnt this be paged?
/// <summary> Gets the user in this guild with the provided id, or null if not found. </summary>
/// <summary>
/// Gets a collection of all users in this guild.
/// </summary>
/// <remarks>
/// This method retrieves all users found within this guild.
/// <note>
/// This may return an incomplete collection in the WebSocket implementation due to how Discord does not
/// send a complete user list for large guilds.
/// </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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a collection of guild
/// users found within this guild.
/// </returns>
Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary>
/// Gets a user from this guild.
/// </summary>
/// <remarks>
/// This method retrieves a user found within this guild.
/// <note>
/// This may return <c>null</c> in the WebSocket implementation due to incomplete user collection in
/// large guilds.
/// </note>
/// </remarks>
/// <param name="id">The snowflake identifier of the user.</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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the guild user
/// associated with the specified <paramref name="id"/>; <c>null</c> if none is found.
/// </returns>
Task<IGuildUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the current user for this guild. </summary>
/// <summary>
/// Gets the current user for this guild.
/// </summary>
/// <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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the currently logged-in
/// user within this guild.
/// </returns>
Task<IGuildUser> GetCurrentUserAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the owner of this guild. </summary>
/// <summary>
/// Gets the owner of this guild.
/// </summary>
/// <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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the owner of this guild.
/// </returns>
Task<IGuildUser> GetOwnerAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Downloads all users for this guild if the current list is incomplete. </summary>
/// <summary>
/// Downloads all users for this guild if the current list is incomplete.
/// </summary>
/// <returns>
/// A task that represents the asynchronous download operation.
/// </returns>
Task DownloadUsersAsync();
/// <summary> Removes all users from this guild if they have not logged on in a provided number of days or, if simulate is true, returns the number of users that would be removed. </summary>
/// <summary>
/// Prunes inactive users.
/// </summary>
/// <remarks>
/// <para>
/// This method removes all users that have not logged on in the provided number of <paramref name="days"/>.
/// </para>
/// <para>
/// If <paramref name="simulate" /> is <c>true</c>, this method will only return the number of users that
/// would be removed without kicking the users.
/// </para>
/// </remarks>
/// <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="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous prune operation. The task result contains the number of users to
/// be or has been removed from this guild.
/// </returns>
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>
/// <summary>
/// Gets the specified number of audit log entries for this guild.
/// </summary>
/// <param name="limit">The number of audit log entries to fetch.</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>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection
/// of the requested audit log entries.
/// </returns>
Task<IReadOnlyCollection<IAuditLogEntry>> GetAuditLogsAsync(int limit = DiscordConfig.MaxAuditLogEntriesPerBatch,
CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
/// <summary> Gets the webhook in this guild with the provided id, or null if not found. </summary>
/// <summary>
/// Gets a webhook found within this guild.
/// </summary>
/// <param name="id">The identifier for the webhook.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the webhook with the
/// specified <paramref name="id"/>; <c>null</c> if none is found.
/// </returns>
Task<IWebhook> GetWebhookAsync(ulong id, RequestOptions options = null);
/// <summary> Gets a collection of all webhooks for this guild. </summary>
/// <summary>
/// Gets a collection of all webhook from this guild.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection
/// of webhooks found within the guild.
/// </returns>
Task<IReadOnlyCollection<IWebhook>> GetWebhooksAsync(RequestOptions options = null);
/// <summary> Gets a specific emote from this guild. </summary>
/// <summary>
/// Gets a specific emote from this guild.
/// </summary>
/// <param name="id">The snowflake identifier for the guild emote.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains the emote found with the
/// specified <paramref name="id"/>; <c>null</c> if none is found.
/// </returns>
Task<GuildEmote> GetEmoteAsync(ulong id, RequestOptions options = null);
/// <summary> Creates a new emote in this guild. </summary>
/// <summary>
/// Creates a new <see cref="GuildEmote"/> in this guild.
/// </summary>
/// <param name="name">The name of the guild emote.</param>
/// <param name="image">The image of the new emote.</param>
/// <param name="roles">The roles to limit the emote usage to.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous creation operation. The task result contains the created emote.
/// </returns>
Task<GuildEmote> CreateEmoteAsync(string name, Image image, Optional<IEnumerable<IRole>> roles = default(Optional<IEnumerable<IRole>>), RequestOptions options = null);
/// <summary> Modifies an existing emote in this guild. </summary>
/// <summary>
/// Modifies an existing <see cref="GuildEmote"/> in this guild.
/// </summary>
/// <param name="emote">The emote to be modified.</param>
/// <param name="func">The delegate containing the properties to modify the emote with.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous modification operation. The task result contains the modified
/// emote.
/// </returns>
Task<GuildEmote> ModifyEmoteAsync(GuildEmote emote, Action<EmoteProperties> func, RequestOptions options = null);
/// <summary> Deletes an existing emote from this guild. </summary>
/// <summary>
/// Deletes an existing <see cref="GuildEmote"/> from this guild.
/// </summary>
/// <param name="emote">The emote to delete.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous removal operation.
/// </returns>
Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null);
}
}

View File

@@ -1,17 +1,69 @@
using System;
using System;
namespace Discord
{
/// <summary>
/// Holds information for a guild integration feature.
/// </summary>
public interface IGuildIntegration
{
/// <summary>
/// Gets the integration ID.
/// </summary>
/// <returns>
/// An <see cref="UInt64"/> representing the unique identifier value of this integration.
/// </returns>
ulong Id { get; }
/// <summary>
/// Gets the integration name.
/// </summary>
/// <returns>
/// A string containing the name of this integration.
/// </returns>
string Name { get; }
/// <summary>
/// Gets the integration type (Twitch, YouTube, etc).
/// </summary>
/// <returns>
/// A string containing the name of the type of integration.
/// </returns>
string Type { get; }
/// <summary>
/// Gets a value that indicates whether this integration is enabled or not.
/// </summary>
/// <returns>
/// <c>true</c> if this integration is enabled; otherwise <c>false</c>.
/// </returns>
bool IsEnabled { get; }
/// <summary>
/// Gets a value that indicates whether this integration is syncing or not.
/// </summary>
/// <remarks>
/// An integration with syncing enabled will update its "subscribers" on an interval, while one with syncing
/// disabled will not. A user must manually choose when sync the integration if syncing is disabled.
/// </remarks>
/// <returns>
/// <c>true</c> if this integration is syncing; otherwise <c>false</c>.
/// </returns>
bool IsSyncing { get; }
/// <summary>
/// Gets the ID that this integration uses for "subscribers".
/// </summary>
ulong ExpireBehavior { get; }
/// <summary>
/// Gets the grace period before expiring "subscribers".
/// </summary>
ulong ExpireGracePeriod { get; }
/// <summary>
/// Gets when this integration was last synced.
/// </summary>
/// <returns>
/// A <see cref="DateTimeOffset"/> containing a date and time of day when the integration was last synced.
/// </returns>
DateTimeOffset SyncedAt { get; }
/// <summary>
/// Gets integration account information.
/// </summary>
IntegrationAccount Account { get; }
IGuild Guild { get; }

View File

@@ -1,14 +1,22 @@
namespace Discord
namespace Discord
{
public interface IUserGuild : IDeletable, ISnowflakeEntity
{
/// <summary> Gets the name of this guild. </summary>
/// <summary>
/// Gets the name of this guild.
/// </summary>
string Name { get; }
/// <summary> Returns the url to this guild's icon, or null if one is not set. </summary>
/// <summary>
/// Gets the icon URL associated with this guild, or <c>null</c> if one is not set.
/// </summary>
string IconUrl { get; }
/// <summary> Returns true if the current user owns this guild. </summary>
/// <summary>
/// Returns <c>true</c> if the current user owns this guild.
/// </summary>
bool IsOwner { get; }
/// <summary> Returns the current user's permissions for this guild. </summary>
/// <summary>
/// Returns the current user's permissions for this guild.
/// </summary>
GuildPermissions Permissions { get; }
}
}

View File

@@ -1,18 +1,51 @@
namespace Discord
{
/// <summary>
/// Represents a region of which the user connects to when using voice.
/// </summary>
public interface IVoiceRegion
{
/// <summary> Gets the unique identifier for this voice region. </summary>
/// <summary>
/// Gets the unique identifier for this voice region.
/// </summary>
/// <returns>
/// A string that represents the identifier for this voice region (e.g. <c>eu-central</c>).
/// </returns>
string Id { get; }
/// <summary> Gets the name of this voice region. </summary>
/// <summary>
/// Gets the name of this voice region.
/// </summary>
/// <returns>
/// A string that represents the human-readable name of this voice region (e.g. <c>Central Europe</c>).
/// </returns>
string Name { get; }
/// <summary> Returns true if this voice region is exclusive to VIP accounts. </summary>
/// <summary>
/// Gets a value that indicates whether or not this voice region is exclusive to partnered servers.
/// </summary>
/// <returns>
/// <c>true</c> if this voice region is exclusive to VIP accounts; otherwise <c>false</c>.
/// </returns>
bool IsVip { get; }
/// <summary> Returns true if this voice region is the closest to your machine. </summary>
/// <summary>
/// Gets a value that indicates whether this voice region is optimal for your client in terms of latency.
/// </summary>
/// <returns>
/// <c>true</c> if this voice region is the closest to your machine; otherwise <c>false</c> .
/// </returns>
bool IsOptimal { get; }
/// <summary> Returns true if this is a deprecated voice region (avoid switching to these). </summary>
/// <summary>
/// Gets a value that indicates whether this voice region is no longer being maintained.
/// </summary>
/// <returns>
/// <c>true</c> if this is a deprecated voice region; otherwise <c>false</c>.
/// </returns>
bool IsDeprecated { get; }
/// <summary> Returns true if this is a custom voice region (used for events/etc) </summary>
/// <summary>
/// Gets a value that indicates whether this voice region is custom-made for events.
/// </summary>
/// <returns>
/// <c>true</c> if this is a custom voice region (used for events/etc); otherwise <c>false</c>/
/// </returns>
bool IsCustom { get; }
}
}

View File

@@ -1,11 +1,15 @@
using System.Diagnostics;
using System.Diagnostics;
namespace Discord
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct IntegrationAccount
{
/// <summary> Gets the ID of the account. </summary>
/// <returns> A <see cref="string"/> unique identifier of this integration account. </returns>
public string Id { get; }
/// <summary> Gets the name of the account. </summary>
/// <returns> A string containing the name of this integration account. </returns>
public string Name { get; private set; }
public override string ToString() => Name;

View File

@@ -1,10 +1,17 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Specifies the guild's Multi-Factor Authentication (MFA) level requirement.
/// </summary>
public enum MfaLevel
{
/// <summary> Users have no additional MFA restriction on this guild. </summary>
/// <summary>
/// Users have no additional MFA restriction on this guild.
/// </summary>
Disabled = 0,
/// <summary> Users must have MFA enabled on their account to perform administrative actions. </summary>
/// <summary>
/// Users must have MFA enabled on their account to perform administrative actions.
/// </summary>
Enabled = 1
}
}

View File

@@ -1,8 +1,17 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Specifies the target of the permission.
/// </summary>
public enum PermissionTarget
{
/// <summary>
/// The target of the permission is a role.
/// </summary>
Role,
/// <summary>
/// The target of the permission is a user.
/// </summary>
User
}
}

View File

@@ -1,16 +1,29 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Specifies the verification level the guild uses.
/// </summary>
public enum VerificationLevel
{
/// <summary> Users have no additional restrictions on sending messages to this guild. </summary>
/// <summary>
/// Users have no additional restrictions on sending messages to this guild.
/// </summary>
None = 0,
/// <summary> Users must have a verified email on their account. </summary>
/// <summary>
/// Users must have a verified email on their account.
/// </summary>
Low = 1,
/// <summary> Users must fulfill the requirements of Low, and be registered on Discord for at least 5 minutes. </summary>
/// <summary>
/// Users must fulfill the requirements of Low and be registered on Discord for at least 5 minutes.
/// </summary>
Medium = 2,
/// <summary> Users must fulfill the requirements of Medium, and be a member of this guild for at least 10 minutes. </summary>
/// <summary>
/// Users must fulfill the requirements of Medium and be a member of this guild for at least 10 minutes.
/// </summary>
High = 3,
/// <summary> Users must fulfill the requirements of High, and must have a verified phone on their Discord account. </summary>
/// <summary>
/// Users must fulfill the requirements of High and must have a verified phone on their Discord account.
/// </summary>
Extreme = 4
}
}

View File

@@ -1,13 +1,31 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Represents a Discord application created via the developer portal.
/// </summary>
public interface IApplication : ISnowflakeEntity
{
/// <summary>
/// Gets the name of the application.
/// </summary>
string Name { get; }
/// <summary>
/// Gets the description of the application.
/// </summary>
string Description { get; }
/// <summary>
/// Gets the RPC origins of the application.
/// </summary>
string[] RPCOrigins { get; }
ulong Flags { get; }
/// <summary>
/// Gets the icon URL of the application.
/// </summary>
string IconUrl { get; }
/// <summary>
/// Gets the partial user object containing info on the owner of the application.
/// </summary>
IUser Owner { get; }
}
}

View File

@@ -1,10 +1,16 @@
using System.Threading.Tasks;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Determines whether the object is deletable or not.
/// </summary>
public interface IDeletable
{
/// <summary> Deletes this object and all its children. </summary>
/// <summary>
/// Deletes this object and all its children.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
Task DeleteAsync(RequestOptions options = null);
}
}

View File

@@ -8,7 +8,9 @@ namespace Discord
///// <summary> Gets the IDiscordClient that created this object. </summary>
//IDiscordClient Discord { get; }
/// <summary> Gets the unique identifier for this object. </summary>
/// <summary>
/// Gets the unique identifier for this object.
/// </summary>
TId Id { get; }
}

View File

@@ -1,8 +1,16 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Determines whether the object is mentionable or not.
/// </summary>
public interface IMentionable
{
/// <summary> Returns a special string used to mention this object. </summary>
/// <summary>
/// Returns a special string used to mention this object.
/// </summary>
/// <returns>
/// A string that is recognized by Discord as a mention (e.g. &lt;@168693960628371456&gt;).
/// </returns>
string Mention { get; }
}
}

View File

@@ -2,8 +2,15 @@ using System;
namespace Discord
{
/// <summary> Represents a Discord snowflake entity. </summary>
public interface ISnowflakeEntity : IEntity<ulong>
{
/// <summary>
/// Gets when the snowflake was created.
/// </summary>
/// <returns>
/// A <see cref="DateTimeOffset"/> representing when the entity was first created.
/// </returns>
DateTimeOffset CreatedAt { get; }
}
}

View File

@@ -1,10 +1,15 @@
using System.Threading.Tasks;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Defines whether the object is updateable or not.
/// </summary>
public interface IUpdateable
{
/// <summary> Updates this object's properties with its current state. </summary>
/// <summary>
/// Updates this object's properties with its current state.
/// </summary>
Task UpdateAsync(RequestOptions options = null);
}
}

View File

@@ -2,27 +2,54 @@ using System.IO;
namespace Discord
{
/// <summary>
/// An image that will be uploaded to Discord.
/// An image that will be uploaded to Discord.
/// </summary>
public struct Image
{
/// <summary>
/// Gets the stream to be uploaded to Discord.
/// </summary>
public Stream Stream { get; }
/// <summary>
/// Create the image with a Stream.
/// Create the image with a <see cref="System.IO.Stream"/>.
/// </summary>
/// <param name="stream">This must be some type of stream with the contents of a file in it.</param>
/// <param name="stream">
/// The <see cref="System.IO.Stream" /> to create the image with. Note that this must be some type of stream
/// with the contents of a file in it.
/// </param>
public Image(Stream stream)
{
Stream = stream;
}
/// <summary>
/// Create the image from a file path.
/// Create the image from a file path.
/// </summary>
/// <remarks>
/// This file path is NOT validated, and is passed directly into a <see cref="File.OpenRead(string)"/>
/// This file path is NOT validated and is passed directly into a
/// <see cref="File.OpenRead"/>.
/// </remarks>
/// <param name="path">The path to the file.</param>
/// <exception cref="System.ArgumentException">
/// <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"/>.
/// </exception>
/// <exception cref="System.ArgumentNullException"><paramref name="path" /> is <c>null</c>.</exception>
/// <exception cref="PathTooLongException">
/// 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
/// characters.
/// </exception>
/// <exception cref="System.NotSupportedException"><paramref name="path" /> is in an invalid format.</exception>
/// <exception cref="DirectoryNotFoundException">
/// The specified <paramref name="path"/> is invalid, (for example, it is on an unmapped drive).
/// </exception>
/// <exception cref="System.UnauthorizedAccessException">
/// <paramref name="path" /> specified a directory.-or- The caller does not have the required permission.
/// </exception>
/// <exception cref="FileNotFoundException">The file specified in <paramref name="path" /> was not found.
/// </exception>
/// <exception cref="IOException">An I/O error occurred while opening the file. </exception>
public Image(string path)
{
Stream = File.OpenRead(path);

View File

@@ -1,11 +1,29 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Specifies the type of format the image should return in.
/// </summary>
public enum ImageFormat
{
/// <summary>
/// Use automatically detected format.
/// </summary>
Auto,
/// <summary>
/// Use Google's WebP image format.
/// </summary>
WebP,
/// <summary>
/// Use PNG.
/// </summary>
Png,
/// <summary>
/// Use JPEG.
/// </summary>
Jpeg,
/// <summary>
/// Use GIF.
/// </summary>
Gif,
}
}

View File

@@ -1,30 +1,85 @@
namespace Discord
{
/// <summary>
/// Represents a generic invite object.
/// </summary>
public interface IInvite : IEntity<string>, IDeletable
{
/// <summary> Gets the unique identifier for this invite. </summary>
/// <summary>
/// Gets the unique identifier for this invite.
/// </summary>
/// <returns>
/// A string containing the invite code (e.g. <c>FTqNnyS</c>).
/// </returns>
string Code { get; }
/// <summary> Gets the url used to accept this invite, using Code. </summary>
/// <summary>
/// Gets the URL used to accept this invite using <see cref="Code"/>.
/// </summary>
/// <returns>
/// A string containing the full invite URL (e.g. <c>https://discord.gg/FTqNnyS</c>).
/// </returns>
string Url { get; }
/// <summary> Gets the channel this invite is linked to. </summary>
/// <summary>
/// Gets the channel this invite is linked to.
/// </summary>
/// <returns>
/// A generic channel that the invite points to.
/// </returns>
IChannel Channel { get; }
/// <summary> Gets the type of the channel this invite is linked to. </summary>
ChannelType ChannelType { get; }
/// <summary> Gets the id of the channel this invite is linked to. </summary>
/// <summary>
/// Gets the ID of the channel this invite is linked to.
/// </summary>
/// <returns>
/// An <see cref="ulong"/> representing the channel snowflake identifier that the invite points to.
/// </returns>
ulong ChannelId { get; }
/// <summary> Gets the name of the channel this invite is linked to. </summary>
/// <summary>
/// Gets the name of the channel this invite is linked to.
/// </summary>
/// <returns>
/// A string containing the name of the channel that the invite points to.
/// </returns>
string ChannelName { get; }
/// <summary> Gets the guild this invite is linked to. </summary>
/// <summary>
/// Gets the guild this invite is linked to.
/// </summary>
/// <returns>
/// A guild object representing the guild that the invite points to.
/// </returns>
IGuild Guild { get; }
/// <summary> Gets the id of the guild this invite is linked to. </summary>
/// <summary>
/// Gets the ID of the guild this invite is linked to.
/// </summary>
/// <returns>
/// An <see cref="ulong"/> representing the guild snowflake identifier that the invite points to.
/// </returns>
ulong? GuildId { get; }
/// <summary> Gets the name of the guild this invite is linked to. </summary>
/// <summary>
/// Gets the name of the guild this invite is linked to.
/// </summary>
/// <returns>
/// A string containing the name of the guild that the invite points to.
/// </returns>
string GuildName { get; }
/// <summary> Gets the approximated count of online members in the guild. </summary>
/// <summary>
/// Gets the approximated count of online members in the guild.
/// </summary>
/// <returns>
/// An <see cref="System.Int32" /> representing the approximated online member count of the guild that the
/// invite points to; <c>null</c> if one cannot be obtained.
/// </returns>
int? PresenceCount { get; }
/// <summary> Gets the approximated count of total members in the guild. </summary>
/// <summary>
/// Gets the approximated count of total members in the guild.
/// </summary>
/// <returns>
/// An <see cref="System.Int32" /> representing the approximated total member count of the guild that the
/// invite points to; <c>null</c> if one cannot be obtained.
/// </returns>
int? MemberCount { get; }
}
}

View File

@@ -2,21 +2,62 @@ using System;
namespace Discord
{
/// <summary>
/// Represents additional information regarding the generic invite object.
/// </summary>
public interface IInviteMetadata : IInvite
{
/// <summary> Gets the user that created this invite. </summary>
/// <summary>
/// Gets the user that created this invite.
/// </summary>
/// <returns>
/// A user that created this invite.
/// </returns>
IUser Inviter { get; }
/// <summary> Returns true if this invite was revoked. </summary>
/// <summary>
/// Gets a value that indicates whether the invite has been revoked.
/// </summary>
/// <returns>
/// <c>true</c> if this invite was revoked; otherwise <c>false</c>.
/// </returns>
bool IsRevoked { get; }
/// <summary> Returns true if users accepting this invite will be removed from the guild when they log off. </summary>
/// <summary>
/// Gets a value that indicates whether the invite is a temporary one.
/// </summary>
/// <returns>
/// <c>true</c> if users accepting this invite will be removed from the guild when they log off; otherwise
/// <c>false</c>.
/// </returns>
bool IsTemporary { get; }
/// <summary> Gets the time (in seconds) until the invite expires, or null if it never expires. </summary>
/// <summary>
/// Gets the time (in seconds) until the invite expires.
/// </summary>
/// <returns>
/// An <see cref="int"/> representing the time in seconds until this invite expires; <c>null</c> if this
/// invite never expires.
/// </returns>
int? MaxAge { get; }
/// <summary> Gets the max amount of times this invite may be used, or null if there is no limit. </summary>
/// <summary>
/// Gets the max number of uses this invite may have.
/// </summary>
/// <returns>
/// An <see cref="int"/> representing the number of uses this invite may be accepted until it is removed
/// from the guild; <c>null</c> if none is set.
/// </returns>
int? MaxUses { get; }
/// <summary> Gets the amount of times this invite has been used. </summary>
/// <summary>
/// Gets the number of times this invite has been used.
/// </summary>
/// <returns>
/// An <see cref="int"/> representing the number of times this invite has been used.
/// </returns>
int? Uses { get; }
/// <summary> Gets when this invite was created. </summary>
/// <summary>
/// Gets when this invite was created.
/// </summary>
/// <returns>
/// A <see cref="DateTimeOffset"/> representing the time of which the invite was first created.
/// </returns>
DateTimeOffset? CreatedAt { get; }
}
}

View File

@@ -5,22 +5,38 @@ using System.Linq;
namespace Discord
{
/// <summary>
/// Represents an embed object seen in an <see cref="IUserMessage"/>.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class Embed : IEmbed
{
/// <inheritdoc/>
public EmbedType Type { get; }
/// <inheritdoc/>
public string Description { get; internal set; }
/// <inheritdoc/>
public string Url { get; internal set; }
/// <inheritdoc/>
public string Title { get; internal set; }
/// <inheritdoc/>
public DateTimeOffset? Timestamp { get; internal set; }
/// <inheritdoc/>
public Color? Color { get; internal set; }
/// <inheritdoc/>
public EmbedImage? Image { get; internal set; }
/// <inheritdoc/>
public EmbedVideo? Video { get; internal set; }
/// <inheritdoc/>
public EmbedAuthor? Author { get; internal set; }
/// <inheritdoc/>
public EmbedFooter? Footer { get; internal set; }
/// <inheritdoc/>
public EmbedProvider? Provider { get; internal set; }
/// <inheritdoc/>
public EmbedThumbnail? Thumbnail { get; internal set; }
/// <inheritdoc/>
public ImmutableArray<EmbedField> Fields { get; internal set; }
internal Embed(EmbedType type)
@@ -57,6 +73,9 @@ namespace Discord
Fields = fields;
}
/// <summary>
/// Gets the total length of all embed properties.
/// </summary>
public int Length
{
get
@@ -70,6 +89,9 @@ namespace Discord
}
}
/// <summary>
/// Gets the title of the embed.
/// </summary>
public override string ToString() => Title;
private string DebuggerDisplay => $"{Title} ({Type})";
}

View File

@@ -1,14 +1,28 @@
using System;
using System.Diagnostics;
namespace Discord
{
/// <summary>
/// A author field of an <see cref="Embed"/>.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct EmbedAuthor
{
/// <summary>
/// Gets the name of the author field.
/// </summary>
public string Name { get; internal set; }
/// <summary>
/// Gets the URL of the author field.
/// </summary>
public string Url { get; internal set; }
/// <summary>
/// Gets the icon URL of the author field.
/// </summary>
public string IconUrl { get; internal set; }
/// <summary>
/// Gets the proxified icon URL of the author field.
/// </summary>
public string ProxyIconUrl { get; internal set; }
internal EmbedAuthor(string name, string url, string iconUrl, string proxyIconUrl)
@@ -20,6 +34,12 @@ namespace Discord
}
private string DebuggerDisplay => $"{Name} ({Url})";
/// <summary>
/// Gets the name of the author field.
/// </summary>
/// <returns>
///
/// </returns>
public override string ToString() => Name;
}
}

View File

@@ -5,6 +5,9 @@ using System.Linq;
namespace Discord
{
/// <summary>
/// Represents a builder class for creating a <see cref="EmbedType.Rich"/> <see cref="Embed"/>.
/// </summary>
public class EmbedBuilder
{
private string _title;
@@ -14,16 +17,33 @@ namespace Discord
private EmbedThumbnail? _thumbnail;
private List<EmbedFieldBuilder> _fields;
/// <summary>
/// Returns the maximum number of fields allowed by Discord.
/// </summary>
public const int MaxFieldCount = 25;
/// <summary>
/// Returns the maximum length of title allowed by Discord.
/// </summary>
public const int MaxTitleLength = 256;
/// <summary>
/// Returns the maximum length of description allowed by Discord.
/// </summary>
public const int MaxDescriptionLength = 2048;
/// <summary>
/// Returns the maximum length of total characters allowed by Discord.
/// </summary>
public const int MaxEmbedLength = 6000;
/// <summary> Initializes a new <see cref="EmbedBuilder"/> class. </summary>
public EmbedBuilder()
{
Fields = new List<EmbedFieldBuilder>();
}
/// <summary> Gets or sets the title of an <see cref="Embed"/>. </summary>
/// <exception cref="ArgumentException" accessor="set">Title length exceeds <see cref="MaxTitleLength"/>.
/// </exception>
/// <returns> The title of the embed.</returns>
public string Title
{
get => _title;
@@ -33,6 +53,10 @@ namespace Discord
_title = value;
}
}
/// <summary> Gets or sets the description of an <see cref="Embed"/>. </summary>
/// <exception cref="ArgumentException" accessor="set">Description length exceeds <see cref="MaxDescriptionLength"/>.</exception>
/// <returns> The description of the embed.</returns>
public string Description
{
get => _description;
@@ -43,49 +67,96 @@ namespace Discord
}
}
/// <summary> Gets or sets the URL of an <see cref="Embed"/>. </summary>
/// <exception cref="ArgumentException" accessor="set">Url is not a well-formed <see cref="Uri"/>.</exception>
/// <returns> The URL of the embed.</returns>
public string Url
{
get => _url;
set
{
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI", paramName: nameof(Url));
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI.", paramName: nameof(Url));
_url = value;
}
}
/// <summary> Gets or sets the thumbnail URL of an <see cref="Embed"/>. </summary>
/// <exception cref="ArgumentException" accessor="set">Url is not a well-formed <see cref="Uri"/>.</exception>
/// <returns> The thumbnail URL of the embed.</returns>
public string ThumbnailUrl
{
get => _thumbnail?.Url;
set
{
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI", paramName: nameof(ThumbnailUrl));
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI.", paramName: nameof(ThumbnailUrl));
_thumbnail = new EmbedThumbnail(value, null, null, null);
}
}
/// <summary> Gets or sets the image URL of an <see cref="Embed"/>. </summary>
/// <exception cref="ArgumentException" accessor="set">Url is not a well-formed <see cref="Uri"/>.</exception>
/// <returns> The image URL of the embed.</returns>
public string ImageUrl
{
get => _image?.Url;
set
{
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI", paramName: nameof(ImageUrl));
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI.", paramName: nameof(ImageUrl));
_image = new EmbedImage(value, null, null, null);
}
}
/// <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
/// <c>null</c>.</exception>
/// <exception cref="ArgumentException" accessor="set">Description length exceeds <see cref="MaxFieldCount"/>.
/// </exception>
/// <returns> The list of existing <see cref="EmbedFieldBuilder"/>.</returns>
public List<EmbedFieldBuilder> Fields
{
get => _fields;
set
{
if (value == null) throw new ArgumentNullException(paramName: nameof(Fields), message: "Cannot set an embed builder's fields collection to null");
if (value == null) throw new ArgumentNullException(paramName: nameof(Fields), message: "Cannot set an embed builder's fields collection to null.");
if (value.Count > MaxFieldCount) throw new ArgumentException(message: $"Field count must be less than or equal to {MaxFieldCount}.", paramName: nameof(Fields));
_fields = value;
}
}
/// <summary>
/// Gets or sets the timestamp of an <see cref="Embed"/>.
/// </summary>
/// <returns>
/// The timestamp of the embed, or <c>null</c> if none is set.
/// </returns>
public DateTimeOffset? Timestamp { get; set; }
/// <summary>
/// Gets or sets the sidebar color of an <see cref="Embed"/>.
/// </summary>
/// <returns>
/// The color of the embed, or <c>null</c> if none is set.
/// </returns>
public Color? Color { get; set; }
/// <summary>
/// Gets or sets the <see cref="EmbedAuthorBuilder" /> of an <see cref="Embed"/>.
/// </summary>
/// <returns>
/// The author field builder of the embed, or <c>null</c> if none is set.
/// </returns>
public EmbedAuthorBuilder Author { get; set; }
/// <summary>
/// Gets or sets the <see cref="EmbedFooterBuilder" /> of an <see cref="Embed"/>.
/// </summary>
/// <returns>
/// The footer field builder of the embed, or <c>null</c> if none is set.
/// </returns>
public EmbedFooterBuilder Footer { get; set; }
/// <summary>
/// Gets the total length of all embed properties.
/// </summary>
/// <returns>
/// The combined length of <see cref="Title"/>, <see cref="EmbedAuthor.Name"/>, <see cref="Description"/>,
/// <see cref="EmbedFooter.Text"/>, <see cref="EmbedField.Name"/>, and <see cref="EmbedField.Value"/>.
/// </returns>
public int Length
{
get
@@ -100,52 +171,121 @@ namespace Discord
}
}
/// <summary>
/// Sets the title of an <see cref="Embed"/>.
/// </summary>
/// <param name="title">The title to be set.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithTitle(string title)
{
Title = title;
return this;
}
/// <summary>
/// Sets the description of an <see cref="Embed"/>.
/// </summary>
/// <param name="description"> The description to be set. </param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithDescription(string description)
{
Description = description;
return this;
}
/// <summary>
/// Sets the URL of an <see cref="Embed"/>.
/// </summary>
/// <param name="url"> The URL to be set. </param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithUrl(string url)
{
Url = url;
return this;
}
/// <summary>
/// Sets the thumbnail URL of an <see cref="Embed"/>.
/// </summary>
/// <param name="thumbnailUrl"> The thumbnail URL to be set. </param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithThumbnailUrl(string thumbnailUrl)
{
ThumbnailUrl = thumbnailUrl;
return this;
}
/// <summary>
/// Sets the image URL of an <see cref="Embed"/>.
/// </summary>
/// <param name="imageUrl">The image URL to be set.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithImageUrl(string imageUrl)
{
ImageUrl = imageUrl;
return this;
}
/// <summary>
/// Sets the timestamp of an <see cref="Embed" /> to the current time.
/// </summary>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithCurrentTimestamp()
{
Timestamp = DateTimeOffset.UtcNow;
return this;
}
/// <summary>
/// Sets the timestamp of an <see cref="Embed"/>.
/// </summary>
/// <param name="dateTimeOffset">The timestamp to be set.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithTimestamp(DateTimeOffset dateTimeOffset)
{
Timestamp = dateTimeOffset;
return this;
}
/// <summary>
/// Sets the sidebar color of an <see cref="Embed"/>.
/// </summary>
/// <param name="color">The color to be set.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithColor(Color color)
{
Color = color;
return this;
}
/// <summary>
/// Sets the <see cref="EmbedAuthorBuilder" /> of an <see cref="Embed"/>.
/// </summary>
/// <param name="author">The author builder class containing the author field properties.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithAuthor(EmbedAuthorBuilder author)
{
Author = author;
return this;
}
/// <summary>
/// Sets the author field of an <see cref="Embed" /> with the provided properties.
/// </summary>
/// <param name="action">The delegate containing the author field properties.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithAuthor(Action<EmbedAuthorBuilder> action)
{
var author = new EmbedAuthorBuilder();
@@ -153,6 +293,15 @@ namespace Discord
Author = author;
return this;
}
/// <summary>
/// Sets the author field of an <see cref="Embed" /> with the provided name, icon URL, and URL.
/// </summary>
/// <param name="name">The title of the author field.</param>
/// <param name="iconUrl">The icon URL of the author field.</param>
/// <param name="url">The URL of the author field.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithAuthor(string name, string iconUrl = null, string url = null)
{
var author = new EmbedAuthorBuilder
@@ -164,11 +313,25 @@ namespace Discord
Author = author;
return this;
}
/// <summary>
/// Sets the <see cref="EmbedFooterBuilder" /> of an <see cref="Embed"/>.
/// </summary>
/// <param name="footer">The footer builder class containing the footer field properties.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithFooter(EmbedFooterBuilder footer)
{
Footer = footer;
return this;
}
/// <summary>
/// Sets the footer field of an <see cref="Embed" /> with the provided properties.
/// </summary>
/// <param name="action">The delegate containing the footer field properties.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithFooter(Action<EmbedFooterBuilder> action)
{
var footer = new EmbedFooterBuilder();
@@ -176,6 +339,14 @@ namespace Discord
Footer = footer;
return this;
}
/// <summary>
/// Sets the footer field of an <see cref="Embed" /> with the provided name, icon URL.
/// </summary>
/// <param name="text">The title of the footer field.</param>
/// <param name="iconUrl">The icon URL of the footer field.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder WithFooter(string text, string iconUrl = null)
{
var footer = new EmbedFooterBuilder
@@ -187,6 +358,15 @@ namespace Discord
return this;
}
/// <summary>
/// Adds an <see cref="Embed" /> field with the provided name and value.
/// </summary>
/// <param name="name">The title of the field.</param>
/// <param name="value">The value of the field.</param>
/// <param name="inline">Indicates whether the field is in-line or not.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder AddField(string name, object value, bool inline = false)
{
var field = new EmbedFieldBuilder()
@@ -196,6 +376,16 @@ namespace Discord
AddField(field);
return this;
}
/// <summary>
/// Adds a field with the provided <see cref="EmbedFieldBuilder" /> to an
/// <see cref="Embed"/>.
/// </summary>
/// <param name="field">The field builder class containing the field properties.</param>
/// <exception cref="ArgumentException">Field count exceeds <see cref="MaxFieldCount"/>.</exception>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder AddField(EmbedFieldBuilder field)
{
if (Fields.Count >= MaxFieldCount)
@@ -206,6 +396,13 @@ namespace Discord
Fields.Add(field);
return this;
}
/// <summary>
/// Adds an <see cref="Embed" /> field with the provided properties.
/// </summary>
/// <param name="action">The delegate containing the field properties.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedBuilder AddField(Action<EmbedFieldBuilder> action)
{
var field = new EmbedFieldBuilder();
@@ -214,10 +411,17 @@ namespace Discord
return this;
}
/// <summary>
/// Builds the <see cref="Embed" /> into a Rich Embed ready to be sent.
/// </summary>
/// <returns>
/// The built embed object.
/// </returns>
/// <exception cref="InvalidOperationException">Total embed length exceeds <see cref="MaxEmbedLength"/>.</exception>
public Embed Build()
{
if (Length > MaxEmbedLength)
throw new InvalidOperationException($"Total embed length must be less than or equal to {MaxEmbedLength}");
throw new InvalidOperationException($"Total embed length must be less than or equal to {MaxEmbedLength}.");
var fields = ImmutableArray.CreateBuilder<EmbedField>(Fields.Count);
for (int i = 0; i < Fields.Count; i++)
@@ -227,13 +431,33 @@ namespace Discord
}
}
/// <summary>
/// Represents a builder class for an embed field.
/// </summary>
public class EmbedFieldBuilder
{
private string _name;
private string _value;
/// <summary>
/// Gets the maximum field length for name allowed by Discord.
/// </summary>
public const int MaxFieldNameLength = 256;
/// <summary>
/// Gets the maximum field length for value allowed by Discord.
/// </summary>
public const int MaxFieldValueLength = 1024;
/// <summary>
/// Gets or sets the field name.
/// </summary>
/// <exception cref="ArgumentException">
/// <para>Field name is <c>null</c>, empty or entirely whitespace.</para>
/// <para><c>- or -</c></para>
/// <para>Field name length exceeds <see cref="MaxFieldNameLength"/>.</para>
/// </exception>
/// <returns>
/// The name of the field.
/// </returns>
public string Name
{
get => _name;
@@ -245,6 +469,17 @@ namespace Discord
}
}
/// <summary>
/// Gets or sets the field value.
/// </summary>
/// <exception cref="ArgumentException" accessor="set">
/// <para>Field value is <c>null</c>, empty or entirely whitespace.</para>
/// <para><c>- or -</c></para>
/// <para>Field value length exceeds <see cref="MaxFieldValueLength"/>.</para>
/// </exception>
/// <returns>
/// The value of the field.
/// </returns>
public object Value
{
get => _value;
@@ -256,35 +491,84 @@ namespace Discord
_value = stringValue;
}
}
/// <summary>
/// Gets or sets a value that indicates whether the field should be in-line with each other.
/// </summary>
public bool IsInline { get; set; }
/// <summary>
/// Sets the field name.
/// </summary>
/// <param name="name">The name to set the field name to.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedFieldBuilder WithName(string name)
{
Name = name;
return this;
}
/// <summary>
/// Sets the field value.
/// </summary>
/// <param name="value">The value to set the field value to.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedFieldBuilder WithValue(object value)
{
Value = value;
return this;
}
/// <summary>
/// Determines whether the field should be in-line with each other.
/// </summary>
/// <returns>
/// The current builder.
/// </returns>
public EmbedFieldBuilder WithIsInline(bool isInline)
{
IsInline = isInline;
return this;
}
/// <summary>
/// Builds the field builder into a <see cref="EmbedField" /> class.
/// </summary>
/// <returns>
/// The current builder.
/// </returns>
/// <exception cref="ArgumentException">
/// <para><see cref="Name"/> or <see cref="Value"/> is <c>null</c>, empty or entirely whitespace.</para>
/// <para><c>- or -</c></para>
/// <para><see cref="Name"/> or <see cref="Value"/> exceeds the maximum length allowed by Discord.</para>
/// </exception>
public EmbedField Build()
=> new EmbedField(Name, Value.ToString(), IsInline);
}
/// <summary>
/// Represents a builder class for a author field.
/// </summary>
public class EmbedAuthorBuilder
{
private string _name;
private string _url;
private string _iconUrl;
/// <summary>
/// Gets the maximum author name length allowed by Discord.
/// </summary>
public const int MaxAuthorNameLength = 256;
/// <summary>
/// Gets or sets the author name.
/// </summary>
/// <exception cref="ArgumentException">
/// Author name length is longer than <see cref="MaxAuthorNameLength"/>.
/// </exception>
/// <returns>
/// The author name.
/// </returns>
public string Name
{
get => _name;
@@ -294,52 +578,115 @@ namespace Discord
_name = value;
}
}
/// <summary>
/// Gets or sets the URL of the author field.
/// </summary>
/// <exception cref="ArgumentException" accessor="set">Url is not a well-formed <see cref="Uri"/>.</exception>
/// <returns>
/// The URL of the author field.
/// </returns>
public string Url
{
get => _url;
set
{
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI", paramName: nameof(Url));
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI.", paramName: nameof(Url));
_url = value;
}
}
/// <summary>
/// Gets or sets the icon URL of the author field.
/// </summary>
/// <exception cref="ArgumentException" accessor="set">Url is not a well-formed <see cref="Uri"/>.</exception>
/// <returns>
/// The icon URL of the author field.
/// </returns>
public string IconUrl
{
get => _iconUrl;
set
{
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI", paramName: nameof(IconUrl));
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI.", paramName: nameof(IconUrl));
_iconUrl = value;
}
}
/// <summary>
/// Sets the name of the author field.
/// </summary>
/// <param name="name">The name of the author field.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedAuthorBuilder WithName(string name)
{
Name = name;
return this;
}
/// <summary>
/// Sets the URL of the author field.
/// </summary>
/// <param name="url">The URL of the author field.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedAuthorBuilder WithUrl(string url)
{
Url = url;
return this;
}
/// <summary>
/// Sets the icon URL of the author field.
/// </summary>
/// <param name="iconUrl">The icon URL of the author field.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedAuthorBuilder WithIconUrl(string iconUrl)
{
IconUrl = iconUrl;
return this;
}
/// <summary>
/// Builds the author field to be used.
/// </summary>
/// <exception cref="ArgumentException">
/// <para>Author name length is longer than <see cref="MaxAuthorNameLength"/>.</para>
/// <para><c>- or -</c></para>
/// <para><see cref="Url"/> is not a well-formed <see cref="Uri"/>.</para>
/// <para><c>- or -</c></para>
/// <para><see cref="IconUrl"/> is not a well-formed <see cref="Uri"/>.</para>
/// </exception>
/// <returns>
/// The built author field.
/// </returns>
public EmbedAuthor Build()
=> new EmbedAuthor(Name, Url, IconUrl, null);
}
/// <summary>
/// Represents a builder class for an embed footer.
/// </summary>
public class EmbedFooterBuilder
{
private string _text;
private string _iconUrl;
/// <summary>
/// Gets the maximum footer length allowed by Discord.
/// </summary>
public const int MaxFooterTextLength = 2048;
/// <summary>
/// Gets or sets the footer text.
/// </summary>
/// <exception cref="ArgumentException">
/// Author name length is longer than <see cref="MaxFooterTextLength"/>.
/// </exception>
/// <returns>
/// The footer text.
/// </returns>
public string Text
{
get => _text;
@@ -349,27 +696,60 @@ namespace Discord
_text = value;
}
}
/// <summary>
/// Gets or sets the icon URL of the footer field.
/// </summary>
/// <exception cref="ArgumentException" accessor="set">Url is not a well-formed <see cref="Uri"/>.</exception>
/// <returns>
/// The icon URL of the footer field.
/// </returns>
public string IconUrl
{
get => _iconUrl;
set
{
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI", paramName: nameof(IconUrl));
if (!value.IsNullOrUri()) throw new ArgumentException(message: "Url must be a well-formed URI.", paramName: nameof(IconUrl));
_iconUrl = value;
}
}
/// <summary>
/// Sets the name of the footer field.
/// </summary>
/// <param name="text">The text of the footer field.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedFooterBuilder WithText(string text)
{
Text = text;
return this;
}
/// <summary>
/// Sets the icon URL of the footer field.
/// </summary>
/// <param name="iconUrl">The icon URL of the footer field.</param>
/// <returns>
/// The current builder.
/// </returns>
public EmbedFooterBuilder WithIconUrl(string iconUrl)
{
IconUrl = iconUrl;
return this;
}
/// <summary>
/// Builds the footer field to be used.
/// </summary>
/// <returns></returns>
/// <exception cref="ArgumentException">
/// <para><see cref="Text"/> length is longer than <see cref="MaxFooterTextLength"/>.</para>
/// <para><c>- or -</c></para>
/// <para><see cref="IconUrl"/> is not a well-formed <see cref="Uri"/>.</para>
/// </exception>
/// <returns>
/// A built footer field.
/// </returns>
public EmbedFooter Build()
=> new EmbedFooter(Text, IconUrl, null);
}

View File

@@ -1,12 +1,24 @@
using System.Diagnostics;
using System.Diagnostics;
namespace Discord
{
/// <summary>
/// A field for an <see cref="Embed"/>.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct EmbedField
{
/// <summary>
/// Gets the name of the field.
/// </summary>
public string Name { get; internal set; }
/// <summary>
/// Gets the value of the field.
/// </summary>
public string Value { get; internal set; }
/// <summary>
/// Gets a value that indicates whether the field should be in-line with each other.
/// </summary>
public bool Inline { get; internal set; }
internal EmbedField(string name, string value, bool inline)
@@ -17,6 +29,12 @@ namespace Discord
}
private string DebuggerDisplay => $"{Name} ({Value}";
/// <summary>
/// Gets the name of the field.
/// </summary>
/// <returns>
/// A string that resolves to <see cref="EmbedField.Name"/>.
/// </returns>
public override string ToString() => Name;
}
}

View File

@@ -1,14 +1,32 @@
using System;
using System.Diagnostics;
namespace Discord
{
/// <summary> A footer field for an <see cref="Embed"/>. </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct EmbedFooter
{
public string Text { get; internal set; }
public string IconUrl { get; internal set; }
public string ProxyUrl { get; internal set; }
/// <summary>
/// Gets the text of the footer field.
/// </summary>
/// <returns>
/// A string containing the text of the footer field.
/// </returns>
public string Text { get; }
/// <summary>
/// Gets the URL of the footer icon.
/// </summary>
/// <returns>
/// A string containing the URL of the footer icon.
/// </returns>
public string IconUrl { get; }
/// <summary>
/// Gets the proxied URL of the footer icon link.
/// </summary>
/// <returns>
/// A string containing the proxied URL of the footer icon.
/// </returns>
public string ProxyUrl { get; }
internal EmbedFooter(string text, string iconUrl, string proxyUrl)
{
@@ -18,6 +36,12 @@ namespace Discord
}
private string DebuggerDisplay => $"{Text} ({IconUrl})";
/// <summary>
/// Gets the text of the footer field.
/// </summary>
/// <returns>
/// A string that resolves to <see cref="Discord.EmbedFooter.Text"/>.
/// </returns>
public override string ToString() => Text;
}
}

View File

@@ -1,14 +1,40 @@
using System;
using System.Diagnostics;
namespace Discord
{
/// <summary> An image for an <see cref="Embed"/>. </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct EmbedImage
{
/// <summary>
/// Gets the URL of the image.
/// </summary>
/// <returns>
/// A string containing the URL of the image.
/// </returns>
public string Url { get; }
/// <summary>
/// Gets a proxied URL of this image.
/// </summary>
/// <returns>
/// A string containing the proxied URL of this image.
/// </returns>
public string ProxyUrl { get; }
/// <summary>
/// Gets the height of this image.
/// </summary>
/// <returns>
/// A <see cref="int"/> representing the height of this image if it can be retrieved; otherwise
/// <c>null</c>.
/// </returns>
public int? Height { get; }
/// <summary>
/// Gets the width of this image.
/// </summary>
/// <returns>
/// A <see cref="int"/> representing the width of this image if it can be retrieved; otherwise
/// <c>null</c>.
/// </returns>
public int? Width { get; }
internal EmbedImage(string url, string proxyUrl, int? height, int? width)
@@ -20,6 +46,12 @@ namespace Discord
}
private string DebuggerDisplay => $"{Url} ({(Width != null && Height != null ? $"{Width}x{Height}" : "0x0")})";
/// <summary>
/// Gets the URL of the thumbnail.
/// </summary>
/// <returns>
/// A string that resolves to <see cref="Discord.EmbedImage.Url"/> .
/// </returns>
public override string ToString() => Url;
}
}

View File

@@ -1,12 +1,24 @@
using System;
using System.Diagnostics;
namespace Discord
{
/// <summary> A provider field for an <see cref="Embed"/>. </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct EmbedProvider
{
/// <summary>
/// Gets the name of the provider.
/// </summary>
/// <returns>
/// A string representing the name of the provider.
/// </returns>
public string Name { get; }
/// <summary>
/// Gets the URL of the provider.
/// </summary>
/// <returns>
/// A string representing the link to the provider.
/// </returns>
public string Url { get; }
internal EmbedProvider(string name, string url)
@@ -16,6 +28,12 @@ namespace Discord
}
private string DebuggerDisplay => $"{Name} ({Url})";
/// <summary>
/// Gets the name of the provider.
/// </summary>
/// <returns>
/// A string that resolves to <see cref="Discord.EmbedProvider.Name" />.
/// </returns>
public override string ToString() => Name;
}
}

View File

@@ -1,14 +1,40 @@
using System;
using System.Diagnostics;
namespace Discord
{
/// <summary> A thumbnail featured in an <see cref="Embed"/>. </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct EmbedThumbnail
{
/// <summary>
/// Gets the URL of the thumbnail.
/// </summary>
/// <returns>
/// A string containing the URL of the thumbnail.
/// </returns>
public string Url { get; }
/// <summary>
/// Gets a proxied URL of this thumbnail.
/// </summary>
/// <returns>
/// A string containing the proxied URL of this thumbnail.
/// </returns>
public string ProxyUrl { get; }
/// <summary>
/// Gets the height of this thumbnail.
/// </summary>
/// <returns>
/// A <see cref="int"/> representing the height of this thumbnail if it can be retrieved; otherwise
/// <c>null</c>.
/// </returns>
public int? Height { get; }
/// <summary>
/// Gets the width of this thumbnail.
/// </summary>
/// <returns>
/// A <see cref="int"/> representing the width of this thumbnail if it can be retrieved; otherwise
/// <c>null</c>.
/// </returns>
public int? Width { get; }
internal EmbedThumbnail(string url, string proxyUrl, int? height, int? width)
@@ -20,6 +46,12 @@ namespace Discord
}
private string DebuggerDisplay => $"{Url} ({(Width != null && Height != null ? $"{Width}x{Height}" : "0x0")})";
/// <summary>
/// Gets the URL of the thumbnail.
/// </summary>
/// <returns>
/// A string that resolves to <see cref="Discord.EmbedThumbnail.Url" />.
/// </returns>
public override string ToString() => Url;
}
}

View File

@@ -1,15 +1,45 @@
namespace Discord
{
/// <summary>
/// Specifies the type of embed.
/// </summary>
public enum EmbedType
{
/// <summary>
/// An unknown embed type.
/// </summary>
Unknown = -1,
/// <summary>
/// A rich embed type.
/// </summary>
Rich,
/// <summary>
/// A link embed type.
/// </summary>
Link,
/// <summary>
/// A video embed type.
/// </summary>
Video,
/// <summary>
/// An image embed type.
/// </summary>
Image,
/// <summary>
/// A GIFV embed type.
/// </summary>
Gifv,
/// <summary>
/// An article embed type.
/// </summary>
Article,
/// <summary>
/// A tweet embed type.
/// </summary>
Tweet,
/// <summary>
/// A HTML embed type.
/// </summary>
Html,
}
}

View File

@@ -1,13 +1,35 @@
using System;
using System.Diagnostics;
namespace Discord
{
/// <summary>
/// A video featured in an <see cref="Embed"/>.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct EmbedVideo
{
/// <summary>
/// Gets the URL of the video.
/// </summary>
/// <returns>
/// A string containing the URL of the image.
/// </returns>
public string Url { get; }
/// <summary>
/// Gets the height of the video.
/// </summary>
/// <returns>
/// A <see cref="int"/> representing the height of this video if it can be retrieved; otherwise
/// <c>null</c>.
/// </returns>
public int? Height { get; }
/// <summary>
/// Gets the weight of the video.
/// </summary>
/// <returns>
/// A <see cref="int"/> representing the width of this video if it can be retrieved; otherwise
/// <c>null</c>.
/// </returns>
public int? Width { get; }
internal EmbedVideo(string url, int? height, int? width)
@@ -18,6 +40,12 @@ namespace Discord
}
private string DebuggerDisplay => $"{Url} ({(Width != null && Height != null ? $"{Width}x{Height}" : "0x0")})";
/// <summary>
/// Gets the URL of the video.
/// </summary>
/// <returns>
/// A string that resolves to <see cref="Url"/>.
/// </returns>
public override string ToString() => Url;
}
}

View File

@@ -1,14 +1,59 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Represents a Discord attachment.
/// </summary>
public interface IAttachment
{
/// <summary>
/// Gets the ID of this attachment.
/// </summary>
/// <returns>
/// A snowflake ID associated with this attachment.
/// </returns>
ulong Id { get; }
/// <summary>
/// Gets the filename of this attachment.
/// </summary>
/// <returns>
/// A string containing the full filename of this attachment (e.g. <c>textFile.txt</c>).
/// </returns>
string Filename { get; }
/// <summary>
/// Gets the URL of this attachment.
/// </summary>
/// <returns>
/// A string containing the URL of this attachment.
/// </returns>
string Url { get; }
/// <summary>
/// Gets a proxied URL of this attachment.
/// </summary>
/// <returns>
/// A string containing the proxied URL of this attachment.
/// </returns>
string ProxyUrl { get; }
/// <summary>
/// Gets the file size of this attachment.
/// </summary>
/// <returns>
/// The size of this attachment in bytes.
/// </returns>
int Size { get; }
/// <summary>
/// Gets the height of this attachment.
/// </summary>
/// <returns>
/// The height of this attachment if it is a picture; otherwise <c>null</c>.
/// </returns>
int? Height { get; }
/// <summary>
/// Gets the width of this attachment.
/// </summary>
/// <returns>
/// The width of this attachment if it is a picture; otherwise <c>null</c>.
/// </returns>
int? Width { get; }
}
}

View File

@@ -1,22 +1,104 @@
using System;
using System;
using System.Collections.Immutable;
namespace Discord
{
/// <summary>
/// Represents a Discord embed object.
/// </summary>
public interface IEmbed
{
/// <summary>
/// Gets the title URL of this embed.
/// </summary>
/// <returns>
/// A string containing the URL set in a title of the embed.
/// </returns>
string Url { get; }
/// <summary>
/// Gets the title of this embed.
/// </summary>
/// <returns>
/// The title of the embed.
/// </returns>
string Title { get; }
/// <summary>
/// Gets the description of this embed.
/// </summary>
/// <returns>
/// The description field of the embed.
/// </returns>
string Description { get; }
/// <summary>
/// Gets the type of this embed.
/// </summary>
/// <returns>
/// The type of the embed.
/// </returns>
EmbedType Type { get; }
/// <summary>
/// Gets the timestamp of this embed.
/// </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; }
/// <summary>
/// Gets the color of this embed.
/// </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; }
/// <summary>
/// Gets the image of this embed.
/// </summary>
/// <returns>
/// The image of the embed, or <c>null</c> if none is set.
/// </returns>
EmbedImage? Image { get; }
/// <summary>
/// Gets the video of this embed.
/// </summary>
/// <returns>
/// The video of the embed, or <c>null</c> if none is set.
/// </returns>
EmbedVideo? Video { get; }
/// <summary>
/// Gets the author field of this embed.
/// </summary>
/// <returns>
/// The author field of the embed, or <c>null</c> if none is set.
/// </returns>
EmbedAuthor? Author { get; }
/// <summary>
/// Gets the footer field of this embed.
/// </summary>
/// <returns>
/// The author field of the embed, or <c>null</c> if none is set.
/// </returns>
EmbedFooter? Footer { get; }
/// <summary>
/// Gets the provider of this embed.
/// </summary>
/// <returns>
/// The source of the embed, or <c>null</c> if none is set.
/// </returns>
EmbedProvider? Provider { get; }
/// <summary>
/// Gets the thumbnail featured in this embed.
/// </summary>
/// <returns>
/// The thumbnail featured in the embed, or <c>null</c> if none is set.
/// </returns>
EmbedThumbnail? Thumbnail { get; }
/// <summary>
/// Gets the fields of the embed.
/// </summary>
/// <returns>
/// An array of the fields of the embed.
/// </returns>
ImmutableArray<EmbedField> Fields { get; }
}
}

View File

@@ -1,41 +1,104 @@
using System;
using System;
using System.Collections.Generic;
namespace Discord
{
/// <summary>
/// Represents a message object.
/// </summary>
public interface IMessage : ISnowflakeEntity, IDeletable
{
/// <summary> Gets the type of this system message. </summary>
/// <summary>
/// Gets the type of this system message.
/// </summary>
MessageType Type { get; }
/// <summary> Gets the source of this message. </summary>
/// <summary>
/// Gets the source type of this message.
/// </summary>
MessageSource Source { get; }
/// <summary> Returns true if this message was sent as a text-to-speech message. </summary>
/// <summary>
/// Gets the value that indicates whether this message was meant to be read-aloud by Discord.
/// </summary>
/// <returns>
/// <c>true</c> if this message was sent as a text-to-speech message; otherwise <c>false</c>.
/// </returns>
bool IsTTS { get; }
/// <summary> Returns true if this message was added to its channel's pinned messages. </summary>
/// <summary>
/// Gets the value that indicates whether this message is pinned.
/// </summary>
/// <returns>
/// <c>true</c> if this message was added to its channel's pinned messages; otherwise <c>false</c>.
/// </returns>
bool IsPinned { get; }
/// <summary> Returns the content for this message. </summary>
/// <summary>
/// Gets the content for this message.
/// </summary>
/// <returns>
/// A string that contains the body of the message; note that this field may be empty if there is an embed.
/// </returns>
string Content { get; }
/// <summary> Gets the time this message was sent. </summary>
/// <summary>
/// Gets the time this message was sent.
/// </summary>
/// <returns>
/// Time of when the message was sent.
/// </returns>
DateTimeOffset Timestamp { get; }
/// <summary> Gets the time of this message's last edit, if any. </summary>
/// <summary>
/// Gets the time of this message's last edit.
/// </summary>
/// <returns>
/// Time of when the message was last edited; <c>null</c> when the message is never edited.
/// </returns>
DateTimeOffset? EditedTimestamp { get; }
/// <summary> Gets the channel this message was sent to. </summary>
/// <summary>
/// Gets the source channel of the message.
/// </summary>
IMessageChannel Channel { get; }
/// <summary> Gets the author of this message. </summary>
/// <summary>
/// Gets the author of this message.
/// </summary>
IUser Author { get; }
/// <summary> Returns all attachments included in this message. </summary>
/// <summary>
/// Returns all attachments included in this message.
/// </summary>
/// <returns>
/// A read-only collection of attachments.
/// </returns>
IReadOnlyCollection<IAttachment> Attachments { get; }
/// <summary> Returns all embeds included in this message. </summary>
/// <summary>
/// Returns all embeds included in this message.
/// </summary>
/// <returns>
/// A read-only collection of embed objects.
/// </returns>
IReadOnlyCollection<IEmbed> Embeds { get; }
/// <summary> Returns all tags included in this message's content. </summary>
/// <summary>
/// Returns all tags included in this message's content.
/// </summary>
IReadOnlyCollection<ITag> Tags { get; }
/// <summary> Returns the ids of channels mentioned in this message. </summary>
/// <summary>
/// Returns the IDs of channels mentioned in this message.
/// </summary>
/// <returns>
/// A read-only collection of channel IDs.
/// </returns>
IReadOnlyCollection<ulong> MentionedChannelIds { get; }
/// <summary> Returns the ids of roles mentioned in this message. </summary>
/// <summary>
/// Returns the IDs of roles mentioned in this message.
/// </summary>
/// <returns>
/// A read-only collection of role IDs.
/// </returns>
IReadOnlyCollection<ulong> MentionedRoleIds { get; }
/// <summary> Returns the ids of users mentioned in this message. </summary>
/// <summary>
/// Returns the IDs of users mentioned in this message.
/// </summary>
/// <returns>
/// A read-only collection of user IDs.
/// </returns>
IReadOnlyCollection<ulong> MentionedUserIds { get; }
}
}

View File

@@ -1,7 +1,13 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Represents a generic reaction object.
/// </summary>
public interface IReaction
{
/// <summary>
/// The <see cref="IEmote" /> used in the reaction.
/// </summary>
IEmote Emote { get; }
}
}

View File

@@ -1,5 +1,8 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Represents a generic message sent by the system.
/// </summary>
public interface ISystemMessage : IMessage
{
}

View File

@@ -4,28 +4,114 @@ using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents a generic message sent by a user.
/// </summary>
public interface IUserMessage : IMessage
{
/// <summary> Modifies this message. </summary>
/// <summary>
/// Modifies this message.
/// </summary>
/// <example>
/// <code language="cs">
/// await msg.ModifyAsync(x =&gt; x.Content = "Hello World!");
/// </code>
/// </example>
/// <param name="func">A delegate containing the properties to modify the message with.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous modification operation.
/// </returns>
Task ModifyAsync(Action<MessageProperties> func, RequestOptions options = null);
/// <summary> Adds this message to its channel's pinned messages. </summary>
/// <summary>
/// Adds this message to its channel's pinned messages.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous operation for pinning this message.
/// </returns>
Task PinAsync(RequestOptions options = null);
/// <summary> Removes this message from its channel's pinned messages. </summary>
/// <summary>
/// Removes this message from its channel's pinned messages.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous operation for unpinning this message.
/// </returns>
Task UnpinAsync(RequestOptions options = null);
/// <summary> Returns all reactions included in this message. </summary>
/// <summary>
/// Gets all reactions included in this message.
/// </summary>
IReadOnlyDictionary<IEmote, ReactionMetadata> Reactions { get; }
/// <summary> Adds a reaction to this message. </summary>
/// <summary>
/// Adds a reaction to this message.
/// </summary>
/// <example>
/// <code language="cs">
/// await msg.AddReactionAsync(new Emoji("\U0001f495"));
/// </code>
/// </example>
/// <param name="emote">The emoji used to react to this message.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous operation for adding a reaction to this message.
/// </returns>
/// <seealso cref="IEmote"/>
Task AddReactionAsync(IEmote emote, RequestOptions options = null);
/// <summary> Removes a reaction from message. </summary>
/// <summary>
/// Removes a reaction from message.
/// </summary>
/// <example>
/// <code language="cs">
/// await msg.RemoveReactionAsync(new Emoji("\U0001f495"), msg.Author);
/// </code>
/// </example>
/// <param name="emote">The emoji used to react to this message.</param>
/// <param name="user">The user that added the emoji.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous operation for removing a reaction to this message.
/// </returns>
/// <seealso cref="IEmote"/>
Task RemoveReactionAsync(IEmote emote, IUser user, RequestOptions options = null);
/// <summary> Removes all reactions from this message. </summary>
/// <summary>
/// Removes all reactions from this message.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous removal operation.
/// </returns>
Task RemoveAllReactionsAsync(RequestOptions options = null);
/// <summary> Gets all users that reacted to a message with a given emote </summary>
/// <summary>
/// Gets all users that reacted to a message with a given emote.
/// </summary>
/// <example>
/// <code language="cs">
/// var emoji = new Emoji("\U0001f495");
/// var reactedUsers = await message.GetReactionUsersAsync(emoji, 100).FlattenAsync();
/// </code>
/// </example>
/// <param name="emoji">The emoji that represents the reaction that you wish to get.</param>
/// <param name="limit">The number of users to request.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A paged collection containing a read-only collection of users that has reacted to this message.
/// Flattening the paginated response into a collection of users with
/// <see cref="AsyncEnumerableExtensions.FlattenAsync{T}"/> is required if you wish to access the users.
/// </returns>
IAsyncEnumerable<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emoji, int limit, RequestOptions options = null);
/// <summary> Transforms this message's text into a human readable form by resolving its tags. </summary>
/// <summary>
/// Transforms this message's text into a human-readable form by resolving its tags.
/// </summary>
/// <param name="userHandling">Determines how the user tag should be handled.</param>
/// <param name="channelHandling">Determines how the channel tag should be handled.</param>
/// <param name="roleHandling">Determines how the role tag should be handled.</param>
/// <param name="everyoneHandling">Determines how the @everyone tag should be handled.</param>
/// <param name="emojiHandling">Determines how the emoji tag should be handled.</param>
string Resolve(
TagHandling userHandling = TagHandling.Name,
TagHandling channelHandling = TagHandling.Name,

View File

@@ -1,36 +1,23 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Modify a message with the specified parameters.
/// Properties that are used to modify an <see cref="IUserMessage" /> with the specified changes.
/// </summary>
/// <remarks>
/// The content of a message can be cleared with String.Empty; if and only if an 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>
/// <example>
/// <code language="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.");
/// });
/// </code>
/// </example>
/// <seealso cref="IUserMessage.ModifyAsync"/>
public class MessageProperties
{
/// <summary>
/// The content of the message
/// Gets or sets the content of the message.
/// </summary>
/// <remarks>
/// This must be less than 2000 characters.
/// This must be less than the constant defined by <see cref="DiscordConfig.MaxMessageSize"/>.
/// </remarks>
public Optional<string> Content { get; set; }
/// <summary>
/// The embed the message should display
/// Gets or sets the embed the message should display.
/// </summary>
public Optional<Embed> Embed { get; set; }
}

View File

@@ -1,10 +1,25 @@
namespace Discord
{
/// <summary>
/// Specifies the source of the Discord message.
/// </summary>
public enum MessageSource
{
/// <summary>
/// The message is sent by the system.
/// </summary>
System,
/// <summary>
/// The message is sent by a user.
/// </summary>
User,
/// <summary>
/// The message is sent by a bot.
/// </summary>
Bot,
/// <summary>
/// The message is sent by a webhook.
/// </summary>
Webhook
}
}

View File

@@ -1,13 +1,37 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Specifies the type of message.
/// </summary>
public enum MessageType
{
/// <summary>
/// The default message type.
/// </summary>
Default = 0,
/// <summary>
/// The message when a recipient is added.
/// </summary>
RecipientAdd = 1,
/// <summary>
/// The message when a recipient is removed.
/// </summary>
RecipientRemove = 2,
/// <summary>
/// The message when a user is called.
/// </summary>
Call = 3,
/// <summary>
/// The message when a channel name is changed.
/// </summary>
ChannelNameChange = 4,
/// <summary>
/// The message when a channel icon is changed.
/// </summary>
ChannelIconChange = 5,
/// <summary>
/// The message when another message is pinned.
/// </summary>
ChannelPinnedMessage = 6
}
}

View File

@@ -1,11 +1,24 @@
namespace Discord
namespace Discord
{
/// <summary>
/// A metadata containing reaction information.
/// </summary>
public struct ReactionMetadata
{
/// <summary> Gets the number of reactions </summary>
/// <summary>
/// Gets the number of reactions.
/// </summary>
/// <returns>
/// An <see cref="int"/> representing the number of this reactions that has been added to this message.
/// </returns>
public int ReactionCount { get; internal set; }
/// <summary> Returns true if the current user has used this reaction </summary>
/// <summary>
/// Gets a value that indicates whether the current user has reacted to this.
/// </summary>
/// <returns>
/// <c>true</c> if the user has reacted to the message; otherwise <c>false</c>.
/// </returns>
public bool IsMe { get; internal set; }
}
}

View File

@@ -1,13 +1,39 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Specifies the handling type the tag should use.
/// </summary>
/// <seealso cref="MentionUtils"/>
/// <seealso cref="IUserMessage.Resolve"/>
public enum TagHandling
{
Ignore = 0, //<@53905483156684800> -> <@53905483156684800>
Remove, //<@53905483156684800> ->
Name, //<@53905483156684800> -> @Voltana
NameNoPrefix, //<@53905483156684800> -> Voltana
FullName, //<@53905483156684800> -> @Voltana#8252
FullNameNoPrefix, //<@53905483156684800> -> Voltana#8252
Sanitize //<@53905483156684800> -> <@53905483156684800> (w/ nbsp)
/// <summary>
/// Tag handling is ignored (e.g. &lt;@53905483156684800&gt; -&gt; &lt;@53905483156684800&gt;).
/// </summary>
Ignore = 0,
/// <summary>
/// Removes the tag entirely.
/// </summary>
Remove,
/// <summary>
/// Resolves to username (e.g. &lt;@53905483156684800&gt; -&gt; @Voltana).
/// </summary>
Name,
/// <summary>
/// Resolves to username without mention prefix (e.g. &lt;@53905483156684800&gt; -&gt; Voltana).
/// </summary>
NameNoPrefix,
/// <summary>
/// Resolves to username with discriminator value. (e.g. &lt;@53905483156684800&gt; -&gt; @Voltana#8252).
/// </summary>
FullName,
/// <summary>
/// Resolves to username with discriminator value without mention prefix. (e.g. &lt;@53905483156684800&gt; -&gt; Voltana#8252).
/// </summary>
FullNameNoPrefix,
/// <summary>
/// Sanitizes the tag (e.g. &lt;@53905483156684800&gt; -&gt; &lt;@53905483156684800&gt; (w/ nbsp)).
/// </summary>
Sanitize
}
}

View File

@@ -1,12 +1,19 @@
namespace Discord
namespace Discord
{
/// <summary> Specifies the type of Discord tag. </summary>
public enum TagType
{
/// <summary> The object is an user mention. </summary>
UserMention,
/// <summary> The object is a channel mention. </summary>
ChannelMention,
/// <summary> The object is a role mention. </summary>
RoleMention,
/// <summary> The object is an everyone mention. </summary>
EveryoneMention,
/// <summary> The object is a here mention. </summary>
HereMention,
/// <summary> The object is an emoji. </summary>
Emoji
}
}

View File

@@ -2,38 +2,103 @@ using System;
namespace Discord
{
[FlagsAttribute]
/// <summary> Defines the available permissions for a channel. </summary>
[Flags]
public enum ChannelPermission : ulong
{
// General
CreateInstantInvite = 0x00_00_00_01,
ManageChannels = 0x00_00_00_10,
/// <summary>
/// Allows creation of instant invites.
/// </summary>
CreateInstantInvite = 0x00_00_00_01,
/// <summary>
/// Allows management and editing of channels.
/// </summary>
ManageChannels = 0x00_00_00_10,
// Text
AddReactions = 0x00_00_00_40,
/// <summary>
/// Allows for the addition of reactions to messages.
/// </summary>
AddReactions = 0x00_00_00_40,
/// <summary>
/// Allows for reading of messages. This flag is obsolete, use <see cref = "ViewChannel" /> instead.
/// </summary>
[Obsolete("Use ViewChannel instead.")]
ReadMessages = ViewChannel,
ViewChannel = 0x00_00_04_00,
SendMessages = 0x00_00_08_00,
SendTTSMessages = 0x00_00_10_00,
ManageMessages = 0x00_00_20_00,
EmbedLinks = 0x00_00_40_00,
ReadMessages = ViewChannel,
/// <summary>
/// Allows guild members to view a channel, which includes reading messages in text channels.
/// </summary>
ViewChannel = 0x00_00_04_00,
/// <summary>
/// Allows for sending messages in a channel.
/// </summary>
SendMessages = 0x00_00_08_00,
/// <summary>
/// Allows for sending of text-to-speech messages.
/// </summary>
SendTTSMessages = 0x00_00_10_00,
/// <summary>
/// Allows for deletion of other users messages.
/// </summary>
ManageMessages = 0x00_00_20_00,
/// <summary>
/// Allows links sent by users with this permission will be auto-embedded.
/// </summary>
EmbedLinks = 0x00_00_40_00,
/// <summary>
/// Allows for uploading images and files.
/// </summary>
AttachFiles = 0x00_00_80_00,
ReadMessageHistory = 0x00_01_00_00,
/// <summary>
/// Allows for reading of message history.
/// </summary>
ReadMessageHistory = 0x00_01_00_00,
/// <summary>
/// Allows for using the @everyone tag to notify all users in a channel, and the @here tag to notify all
/// online users in a channel.
/// </summary>
MentionEveryone = 0x00_02_00_00,
/// <summary>
/// Allows the usage of custom emojis from other servers.
/// </summary>
UseExternalEmojis = 0x00_04_00_00,
// Voice
Connect = 0x00_10_00_00,
Speak = 0x00_20_00_00,
MuteMembers = 0x00_40_00_00,
DeafenMembers = 0x00_80_00_00,
/// <summary>
/// Allows for joining of a voice channel.
/// </summary>
Connect = 0x00_10_00_00,
/// <summary>
/// Allows for speaking in a voice channel.
/// </summary>
Speak = 0x00_20_00_00,
/// <summary>
/// Allows for muting members in a voice channel.
/// </summary>
MuteMembers = 0x00_40_00_00,
/// <summary>
/// Allows for deafening of members in a voice channel.
/// </summary>
DeafenMembers = 0x00_80_00_00,
/// <summary>
/// Allows for moving of members between voice channels.
/// </summary>
MoveMembers = 0x01_00_00_00,
UseVAD = 0x02_00_00_00,
/// <summary>
/// Allows for using voice-activity-detection in a voice channel.
/// </summary>
UseVAD = 0x02_00_00_00,
PrioritySpeaker = 0x00_00_01_00,
// More General
/// <summary>
/// Allows management and editing of roles.
/// </summary>
ManageRoles = 0x10_00_00_00,
ManageWebhooks = 0x20_00_00_00,
/// <summary>
/// Allows management and editing of webhooks.
/// </summary>
ManageWebhooks = 0x20_00_00_00,
}
}

View File

@@ -7,19 +7,21 @@ namespace Discord
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public struct ChannelPermissions
{
/// <summary> Gets a blank ChannelPermissions that grants no permissions. </summary>
/// <summary> Gets a blank <see cref="ChannelPermissions"/> that grants no permissions. </summary>
/// <returns> A <see cref="ChannelPermissions"/> structure that does not contain any set permissions. </returns>
public static readonly ChannelPermissions None = new ChannelPermissions();
/// <summary> Gets a 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);
/// <summary> Gets a 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_0000000010100_010001);
/// <summary> Gets a 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);
/// <summary> Gets a 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>
public static readonly ChannelPermissions DM = new ChannelPermissions(0b00000_1000110_1011100110000_000000);
/// <summary> Gets a ChannelPermissions that grants all permissions for group channels. </summary>
/// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for group channels. </summary>
public static readonly ChannelPermissions Group = new ChannelPermissions(0b00000_1000110_0001101100000_000000);
/// <summary> Gets a ChannelPermissions that grants all permissions for a given channelType. </summary>
/// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for a given channel type. </summary>
/// <exception cref="ArgumentException">Unknown channel type.</exception>
public static ChannelPermissions All(IChannel channel)
{
switch (channel)
@@ -29,64 +31,64 @@ namespace Discord
case ICategoryChannel _: return Category;
case IDMChannel _: return DM;
case IGroupChannel _: return Group;
default: throw new ArgumentException(message: "Unknown channel type", paramName: nameof(channel));
default: throw new ArgumentException(message: "Unknown channel type.", paramName: nameof(channel));
}
}
/// <summary> Gets a packed value representing all the permissions in this ChannelPermissions. </summary>
/// <summary> Gets a packed value representing all the permissions in this <see cref="ChannelPermissions"/>. </summary>
public ulong RawValue { get; }
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If True, a user may join channels. </summary>
/// <summary> If <c>true</c>, a user may join channels. </summary>
[Obsolete("Use ViewChannel instead.")]
public bool ReadMessages => ViewChannel;
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If True, a user may use priority speaker in a voice channel. </summary>
/// <summary> If <c>true</c>, a user may use priority speaker in a voice channel. </summary>
public bool PrioritySpeaker => Permissions.GetValue(RawValue, ChannelPermission.PrioritySpeaker);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> Creates a new ChannelPermissions with the provided packed value. </summary>
/// <summary> Creates a new <see cref="ChannelPermissions"/> with the provided packed value. </summary>
public ChannelPermissions(ulong rawValue) { RawValue = rawValue; }
private ChannelPermissions(ulong initialValue,
@@ -139,7 +141,7 @@ namespace Discord
RawValue = value;
}
/// <summary> Creates a new ChannelPermissions with the provided permissions. </summary>
/// <summary> Creates a new <see cref="ChannelPermissions"/> with the provided permissions. </summary>
public ChannelPermissions(
bool createInstantInvite = false,
bool manageChannel = false,
@@ -167,7 +169,7 @@ namespace Discord
speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation, prioritySpeaker, manageRoles, manageWebhooks)
{ }
/// <summary> Creates a new ChannelPermissions from this one, changing the provided non-null permissions. </summary>
/// <summary> Creates a new <see cref="ChannelPermissions"/> from this one, changing the provided non-null permissions. </summary>
public ChannelPermissions Modify(
bool? createInstantInvite = null,
bool? manageChannel = null,

View File

@@ -2,46 +2,163 @@ using System;
namespace Discord
{
[FlagsAttribute]
/// <summary> Defines the available permissions for a channel. </summary>
[Flags]
public enum GuildPermission : ulong
{
// General
/// <summary>
/// Allows creation of instant invites.
/// </summary>
CreateInstantInvite = 0x00_00_00_01,
KickMembers = 0x00_00_00_02,
BanMembers = 0x00_00_00_04,
/// <summary>
/// Allows kicking members.
/// </summary>
/// <remarks>
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
KickMembers = 0x00_00_00_02,
/// <summary>
/// Allows banning members.
/// </summary>
/// <remarks>
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
BanMembers = 0x00_00_00_04,
/// <summary>
/// Allows all permissions and bypasses channel permission overwrites.
/// </summary>
/// <remarks>
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
Administrator = 0x00_00_00_08,
/// <summary>
/// Allows management and editing of channels.
/// </summary>
/// <remarks>
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
ManageChannels = 0x00_00_00_10,
/// <summary>
/// Allows management and editing of the guild.
/// </summary>
/// <remarks>
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
ManageGuild = 0x00_00_00_20,
// Text
/// <summary>
/// Allows for the addition of reactions to messages.
/// </summary>
AddReactions = 0x00_00_00_40,
/// <summary>
/// Allows for viewing of audit logs.
/// </summary>
ViewAuditLog = 0x00_00_00_80,
[Obsolete("Use ViewChannel instead.")]
ReadMessages = ViewChannel,
ViewChannel = 0x00_00_04_00,
SendMessages = 0x00_00_08_00,
/// <summary>
/// Allows for sending of text-to-speech messages.
/// </summary>
SendTTSMessages = 0x00_00_10_00,
/// <summary>
/// Allows for deletion of other users messages.
/// </summary>
/// <remarks>
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
ManageMessages = 0x00_00_20_00,
EmbedLinks = 0x00_00_40_00,
AttachFiles = 0x00_00_80_00,
ReadMessageHistory = 0x00_01_00_00,
MentionEveryone = 0x00_02_00_00,
UseExternalEmojis = 0x00_04_00_00,
/// <summary>
/// Allows links sent by users with this permission will be auto-embedded.
/// </summary>
EmbedLinks = 0x00_00_40_00,
/// <summary>
/// Allows for uploading images and files.
/// </summary>
AttachFiles = 0x00_00_80_00,
/// <summary>
/// Allows for reading of message history.
/// </summary>
ReadMessageHistory = 0x00_01_00_00,
/// <summary>
/// Allows for using the @everyone tag to notify all users in a channel, and the @here tag to notify all
/// online users in a channel.
/// </summary>
MentionEveryone = 0x00_02_00_00,
/// <summary>
/// Allows the usage of custom emojis from other servers.
/// </summary>
UseExternalEmojis = 0x00_04_00_00,
// Voice
/// <summary>
/// Allows for joining of a voice channel.
/// </summary>
Connect = 0x00_10_00_00,
/// <summary>
/// Allows for speaking in a voice channel.
/// </summary>
Speak = 0x00_20_00_00,
/// <summary>
/// Allows for muting members in a voice channel.
/// </summary>
MuteMembers = 0x00_40_00_00,
/// <summary>
/// Allows for deafening of members in a voice channel.
/// </summary>
DeafenMembers = 0x00_80_00_00,
/// <summary>
/// Allows for moving of members between voice channels.
/// </summary>
MoveMembers = 0x01_00_00_00,
/// <summary>
/// Allows for using voice-activity-detection in a voice channel.
/// </summary>
UseVAD = 0x02_00_00_00,
PrioritySpeaker = 0x00_00_01_00,
// General 2
ChangeNickname = 0x04_00_00_00,
/// <summary>
/// Allows for modification of own nickname.
/// </summary>
ChangeNickname = 0x04_00_00_00,
/// <summary>
/// Allows for modification of other users nicknames.
/// </summary>
ManageNicknames = 0x08_00_00_00,
/// <summary>
/// Allows management and editing of roles.
/// </summary>
/// <remarks>
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
ManageRoles = 0x10_00_00_00,
/// <summary>
/// Allows management and editing of webhooks.
/// </summary>
/// <remarks>
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
ManageWebhooks = 0x20_00_00_00,
/// <summary>
/// Allows management and editing of emojis.
/// </summary>
/// <remarks>
/// This permission requires the owner account to use two-factor
/// authentication when used on a guild that has server-wide 2FA enabled.
/// </remarks>
ManageEmojis = 0x40_00_00_00
}
}

View File

@@ -7,32 +7,32 @@ namespace Discord
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public struct GuildPermissions
{
/// <summary> Gets a blank GuildPermissions that grants no permissions. </summary>
/// <summary> Gets a blank <see cref="GuildPermissions"/> that grants no permissions. </summary>
public static readonly GuildPermissions None = new GuildPermissions();
/// <summary> Gets a GuildPermissions that grants all guild permissions for webhook users. </summary>
/// <summary> Gets a <see cref="GuildPermissions"/> that grants all guild permissions for webhook users. </summary>
public static readonly GuildPermissions Webhook = new GuildPermissions(0b00000_0000000_0001101100000_000000);
/// <summary> Gets a GuildPermissions that grants all guild permissions. </summary>
/// <summary> Gets a <see cref="GuildPermissions"/> that grants all guild permissions. </summary>
public static readonly GuildPermissions All = new GuildPermissions(0b11111_1111110_1111111110111_111111);
/// <summary> Gets a packed value representing all the permissions in this GuildPermissions. </summary>
/// <summary> Gets a packed value representing all the permissions in this <see cref="GuildPermissions"/>. </summary>
public ulong RawValue { get; }
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If True, a user may join channels. </summary>
@@ -42,48 +42,48 @@ namespace Discord
public bool ViewChannel => Permissions.GetValue(RawValue, GuildPermission.ViewChannel);
/// <summary> If True, a user may send messages. </summary>
public bool SendMessages => Permissions.GetValue(RawValue, GuildPermission.SendMessages);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If True, a user may use priority speaker in a voice channel. </summary>
public bool PrioritySpeaker => Permissions.GetValue(RawValue, ChannelPermission.PrioritySpeaker);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> If 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);
/// <summary> Creates a new GuildPermissions with the provided packed value. </summary>
/// <summary> Creates a new <see cref="GuildPermissions"/> with the provided packed value. </summary>
public GuildPermissions(ulong rawValue) { RawValue = rawValue; }
private GuildPermissions(ulong initialValue,
@@ -152,7 +152,7 @@ namespace Discord
RawValue = value;
}
/// <summary> Creates a new GuildPermissions with the provided permissions. </summary>
/// <summary> Creates a new <see cref="GuildPermissions"/> structure with the provided permissions. </summary>
public GuildPermissions(
bool createInstantInvite = false,
bool kickMembers = false,
@@ -215,7 +215,7 @@ namespace Discord
manageEmojis: manageEmojis)
{ }
/// <summary> Creates a new GuildPermissions from this one, changing the provided non-null permissions. </summary>
/// <summary> Creates a new <see cref="GuildPermissions"/> from this one, changing the provided non-null permissions. </summary>
public GuildPermissions Modify(
bool? createInstantInvite = null,
bool? kickMembers = null,
@@ -251,8 +251,19 @@ namespace Discord
readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, moveMembers,
useVoiceActivation, prioritySpeaker, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojis);
/// <summary>
/// Returns a value that indicates if a specific <see cref="GuildPermission"/> is enabled
/// in these permissions.
/// </summary>
/// <param name="permission">The permission value to check for.</param>
/// <returns><c>true</c> if the permission is enabled, <c>false</c> otherwise.</returns>
public bool Has(GuildPermission permission) => Permissions.GetValue(RawValue, permission);
/// <summary>
/// Returns a <see cref="List{T}"/> containing all of the <see cref="GuildPermission"/>
/// flags that are enabled.
/// </summary>
/// <returns>A <see cref="List{T}"/> containing <see cref="GuildPermission"/> flags. Empty if none are enabled.</returns>
public List<GuildPermission> ToList()
{
var perms = new List<GuildPermission>();

View File

@@ -1,15 +1,26 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Represent a permission object.
/// </summary>
public struct Overwrite
{
/// <summary> Gets the unique identifier for the object this overwrite is targeting. </summary>
/// <summary>
/// Gets the unique identifier for the object this overwrite is targeting.
/// </summary>
public ulong TargetId { get; }
/// <summary> Gets the type of object this overwrite is targeting. </summary>
/// <summary>
/// Gets the type of object this overwrite is targeting.
/// </summary>
public PermissionTarget TargetType { get; }
/// <summary> Gets the permissions associated with this overwrite entry. </summary>
/// <summary>
/// Gets the permissions associated with this overwrite entry.
/// </summary>
public OverwritePermissions Permissions { get; }
/// <summary> Creates a new Overwrite with provided target information and modified permissions. </summary>
/// <summary>
/// Initializes a new <see cref="Overwrite"/> with provided target information and modified permissions.
/// </summary>
public Overwrite(ulong targetId, PermissionTarget targetType, OverwritePermissions permissions)
{
TargetId = targetId;

View File

@@ -4,21 +4,36 @@ using System.Diagnostics;
namespace Discord
{
/// <summary>
/// Represents a container for a series of overwrite permissions.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public struct OverwritePermissions
{
/// <summary> Gets a blank OverwritePermissions that inherits all permissions. </summary>
/// <summary>
/// Gets a blank <see cref="OverwritePermissions" /> that inherits all permissions.
/// </summary>
public static OverwritePermissions InheritAll { get; } = new OverwritePermissions();
/// <summary> Gets a OverwritePermissions that grants all permissions for a given channelType. </summary>
/// <summary>
/// Gets a <see cref="OverwritePermissions" /> that grants all permissions for the given channel.
/// </summary>
/// <exception cref="ArgumentException">Unknown channel type.</exception>
public static OverwritePermissions AllowAll(IChannel channel)
=> new OverwritePermissions(ChannelPermissions.All(channel).RawValue, 0);
/// <summary> Gets a OverwritePermissions that denies all permissions for a given channelType. </summary>
/// <summary>
/// Gets a <see cref="OverwritePermissions" /> that denies all permissions for the given channel.
/// </summary>
/// <exception cref="ArgumentException">Unknown channel type.</exception>
public static OverwritePermissions DenyAll(IChannel channel)
=> new OverwritePermissions(0, ChannelPermissions.All(channel).RawValue);
/// <summary> Gets a packed value representing all the allowed permissions in this OverwritePermissions. </summary>
/// <summary>
/// Gets a packed value representing all the allowed permissions in this <see cref="OverwritePermissions"/>.
/// </summary>
public ulong AllowValue { get; }
/// <summary> Gets a packed value representing all the denied permissions in this OverwritePermissions. </summary>
/// <summary>
/// Gets a packed value representing all the denied permissions in this <see cref="OverwritePermissions"/>.
/// </summary>
public ulong DenyValue { get; }
/// <summary> If Allowed, a user may create invites. </summary>
@@ -62,7 +77,7 @@ namespace Discord
/// <summary> If Allowed, a user may use voice-activity-detection rather than push-to-talk. </summary>
public PermValue UseVAD => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.UseVAD);
/// <summary> If Allowed, a user may adjust role permissions. This also implictly grants all other permissions. </summary>
/// <summary> If Allowed, a user may adjust role permissions. This also implicitly grants all other permissions. </summary>
public PermValue ManageRoles => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ManageRoles);
/// <summary> If True, a user may edit the webhooks for this channel. </summary>
public PermValue ManageWebhooks => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ManageWebhooks);
@@ -121,7 +136,9 @@ namespace Discord
DenyValue = denyValue;
}
/// <summary> Creates a new ChannelPermissions with the provided permissions. </summary>
/// <summary>
/// Initializes a new <see cref="ChannelPermissions"/> struct with the provided permissions.
/// </summary>
public OverwritePermissions(
PermValue createInstantInvite = PermValue.Inherit,
PermValue manageChannel = PermValue.Inherit,
@@ -147,7 +164,10 @@ namespace Discord
embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers,
moveMembers, useVoiceActivation, manageRoles, manageWebhooks) { }
/// <summary> Creates a new OverwritePermissions from this one, changing the provided non-null permissions. </summary>
/// <summary>
/// Initializes a new <see cref="OverwritePermissions" /> from the current one, changing the provided
/// non-null permissions.
/// </summary>
public OverwritePermissions Modify(
PermValue? createInstantInvite = null,
PermValue? manageChannel = null,
@@ -173,6 +193,10 @@ namespace Discord
embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers,
moveMembers, useVoiceActivation, manageRoles, manageWebhooks);
/// <summary>
/// Creates a <see cref="List{T}"/> of all the <see cref="ChannelPermission"/> values that are allowed.
/// </summary>
/// <returns>A <see cref="List{T}"/> of all allowed <see cref="ChannelPermission"/> flags. If none, the list will be empty.</returns>
public List<ChannelPermission> ToAllowList()
{
var perms = new List<ChannelPermission>();
@@ -185,6 +209,11 @@ namespace Discord
}
return perms;
}
/// <summary>
/// Creates a <see cref="List{T}"/> of all the <see cref="ChannelPermission"/> values that are denied.
/// </summary>
/// <returns>A <see cref="List{T}"/> of all denied <see cref="ChannelPermission"/> flags. If none, the list will be empty.</returns>
public List<ChannelPermission> ToDenyList()
{
var perms = new List<ChannelPermission>();

View File

@@ -1,9 +1,13 @@
namespace Discord
namespace Discord
{
/// <summary> Specifies the permission value. </summary>
public enum PermValue
{
/// <summary> Allows this permission. </summary>
Allow,
/// <summary> Denies this permission. </summary>
Deny,
/// <summary> Inherits the permission settings. </summary>
Inherit
}
}

View File

@@ -6,53 +6,79 @@ using StandardColor = System.Drawing.Color;
namespace Discord
{
/// <summary>
/// Represents a color used in Discord.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public struct Color
{
/// <summary> Gets the default user color value. </summary>
public static readonly Color Default = new Color(0);
/// <summary> Gets the teal color value </summary>
/// <summary> Gets the teal color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/1ABC9C">1ABC9C</see>.</returns>
public static readonly Color Teal = new Color(0x1ABC9C);
/// <summary> Gets the dark teal color value </summary>
/// <summary> Gets the dark teal color value. </summary>
public static readonly Color DarkTeal = new Color(0x11806A);
/// <summary> Gets the green color value </summary>
/// <summary> Gets the green color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/11806A">11806A</see>.</returns>
public static readonly Color Green = new Color(0x2ECC71);
/// <summary> Gets the dark green color value </summary>
/// <summary> Gets the dark green color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/2ECC71">2ECC71</see>.</returns>
public static readonly Color DarkGreen = new Color(0x1F8B4C);
/// <summary> Gets the blue color value </summary>
/// <summary> Gets the blue color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/1F8B4C">1F8B4C</see>.</returns>
public static readonly Color Blue = new Color(0x3498DB);
/// <summary> Gets the dark blue color value </summary>
/// <summary> Gets the dark blue color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/3498DB">3498DB</see>.</returns>
public static readonly Color DarkBlue = new Color(0x206694);
/// <summary> Gets the purple color value </summary>
/// <summary> Gets the purple color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/206694">206694</see>.</returns>
public static readonly Color Purple = new Color(0x9B59B6);
/// <summary> Gets the dark purple color value </summary>
/// <summary> Gets the dark purple color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/9B59B6">9B59B6</see>.</returns>
public static readonly Color DarkPurple = new Color(0x71368A);
/// <summary> Gets the magenta color value </summary>
/// <summary> Gets the magenta color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/71368A">71368A</see>.</returns>
public static readonly Color Magenta = new Color(0xE91E63);
/// <summary> Gets the dark magenta color value </summary>
/// <summary> Gets the dark magenta color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/E91E63">E91E63</see>.</returns>
public static readonly Color DarkMagenta = new Color(0xAD1457);
/// <summary> Gets the gold color value </summary>
/// <summary> Gets the gold color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/AD1457">AD1457</see>.</returns>
public static readonly Color Gold = new Color(0xF1C40F);
/// <summary> Gets the light orange color value </summary>
/// <summary> Gets the light orange color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/F1C40F">F1C40F</see>.</returns>
public static readonly Color LightOrange = new Color(0xC27C0E);
/// <summary> Gets the orange color value </summary>
/// <summary> Gets the orange color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/C27C0E">C27C0E</see>.</returns>
public static readonly Color Orange = new Color(0xE67E22);
/// <summary> Gets the dark orange color value </summary>
/// <summary> Gets the dark orange color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/E67E22">E67E22</see>.</returns>
public static readonly Color DarkOrange = new Color(0xA84300);
/// <summary> Gets the red color value </summary>
/// <summary> Gets the red color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/A84300">A84300</see>.</returns>
public static readonly Color Red = new Color(0xE74C3C);
/// <summary> Gets the dark red color value </summary>
/// <summary> Gets the dark red color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/E74C3C">E74C3C</see>.</returns>
public static readonly Color DarkRed = new Color(0x992D22);
/// <summary> Gets the light grey color value </summary>
/// <summary> Gets the light grey color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/992D22">992D22</see>.</returns>
public static readonly Color LightGrey = new Color(0x979C9F);
/// <summary> Gets the lighter grey color value </summary>
/// <summary> Gets the lighter grey color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/979C9F">979C9F</see>.</returns>
public static readonly Color LighterGrey = new Color(0x95A5A6);
/// <summary> Gets the dark grey color value </summary>
/// <summary> Gets the dark grey color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/95A5A6">95A5A6</see>.</returns>
public static readonly Color DarkGrey = new Color(0x607D8B);
/// <summary> Gets the darker grey color value </summary>
/// <summary> Gets the darker grey color value. </summary>
/// <returns> A color struct with the hex value of <see href="http://www.color-hex.com/color/607D8B">607D8B</see>.</returns>
public static readonly Color DarkerGrey = new Color(0x546E7A);
/// <summary> Gets the encoded value for this color. </summary>
/// <remarks>
/// This value is encoded as an unsigned integer value. The most-significant 8 bits contain the red value,
/// the middle 8 bits contain the green value, and the least-significant 8 bits contain the blue value.
/// </remarks>
public uint RawValue { get; }
/// <summary> Gets the red component for this color. </summary>
@@ -62,10 +88,34 @@ namespace Discord
/// <summary> Gets the blue component for this color. </summary>
public byte B => (byte)(RawValue);
/// <summary>
/// Initializes a <see cref="Color"/> struct with the given raw value.
/// </summary>
/// <example>
/// The following will create a color that has a hex value of
/// <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>.
/// <code language="cs">
/// Color darkGrey = new Color(0x607D8B);
/// </code>
/// </example>
/// <param name="rawValue">The raw value of the color (e.g. <c>0x607D8B</c>).</param>
public Color(uint rawValue)
{
RawValue = rawValue;
}
/// <summary>
/// Initializes a <see cref="Color" /> struct with the given RGB bytes.
/// </summary>
/// <example>
/// The following will create a color that has a value of
/// <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>.
/// <code language="cs">
/// Color darkGrey = new Color((byte)0b_01100000, (byte)0b_01111101, (byte)0b_10001011);
/// </code>
/// </example>
/// <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)
{
RawValue =
@@ -73,27 +123,56 @@ namespace Discord
((uint)g << 8) |
(uint)b;
}
/// <summary>
/// Initializes a <see cref="Color"/> struct with the given RGB value.
/// </summary>
/// <example>
/// The following will create a color that has a value of
/// <see href="http://www.color-hex.com/color/607d8b">#607D8B</see>.
/// <code language="cs">
/// Color darkGrey = new Color(96, 125, 139);
/// </code>
/// </example>
/// <param name="r">The value that represents the red color. Must be within 0~255.</param>
/// <param name="g">The value that represents the green color. Must be within 0~255.</param>
/// <param name="b">The value that represents the blue color. Must be within 0~255.</param>
/// <exception cref="ArgumentOutOfRangeException">The argument value is not between 0 to 255.</exception>
public Color(int r, int g, int b)
{
if (r < 0 || r > 255)
throw new ArgumentOutOfRangeException(nameof(r), "Value must be within [0,255]");
throw new ArgumentOutOfRangeException(nameof(r), "Value must be within [0,255].");
if (g < 0 || g > 255)
throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,255]");
throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,255].");
if (b < 0 || b > 255)
throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,255]");
throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,255].");
RawValue =
((uint)r << 16) |
((uint)g << 8) |
(uint)b;
}
/// <summary>
/// Initializes a <see cref="Color"/> struct with the given RGB float value.
/// </summary>
/// <example>
/// The following will create a color that has a value of
/// <see href="http://www.color-hex.com/color/607c8c">#607c8c</see>.
/// <code language="cs">
/// Color darkGrey = new Color(0.38f, 0.49f, 0.55f);
/// </code>
/// </example>
/// <param name="r">The value that represents the red color. Must be within 0~1.</param>
/// <param name="g">The value that represents the green color. Must be within 0~1.</param>
/// <param name="b">The value that represents the blue color. Must be within 0~1.</param>
/// <exception cref="ArgumentOutOfRangeException">The argument value is not between 0 to 1.</exception>
public Color(float r, float g, float b)
{
if (r < 0.0f || r > 1.0f)
throw new ArgumentOutOfRangeException(nameof(r), "Value must be within [0,1]");
throw new ArgumentOutOfRangeException(nameof(r), "Value must be within [0,1].");
if (g < 0.0f || g > 1.0f)
throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,1]");
throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,1].");
if (b < 0.0f || b > 1.0f)
throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,1]");
throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,1].");
RawValue =
((uint)(r * 255.0f) << 16) |
((uint)(g * 255.0f) << 8) |
@@ -118,6 +197,12 @@ namespace Discord
new Color((uint)color.ToArgb() << 8 >> 8);
#endif
/// <summary>
/// Gets the hexadecimal representation of the color (e.g. <c>#000ccc</c>).
/// </summary>
/// <returns>
/// A hexadecimal string of the color.
/// </returns>
public override string ToString() =>
$"#{Convert.ToString(RawValue, 16)}";
private string DebuggerDisplay =>

View File

@@ -1,29 +1,89 @@
using System;
using System;
using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents a generic role object to be given to a guild user.
/// </summary>
public interface IRole : ISnowflakeEntity, IDeletable, IMentionable, IComparable<IRole>
{
/// <summary> Gets the guild owning this role.</summary>
/// <summary>
/// Gets the guild that owns this role.
/// </summary>
/// <returns>
/// A guild representing the parent guild of this role.
/// </returns>
IGuild Guild { get; }
/// <summary> Gets the color given to users of this role. </summary>
/// <summary>
/// Gets the color given to users of this role.
/// </summary>
/// <returns>
/// A <see cref="Color"/> struct representing the color of this role.
/// </returns>
Color Color { get; }
/// <summary> Returns true if users of this role are separated in the user list. </summary>
/// <summary>
/// Gets a value that indicates whether the role can be separated in the user list.
/// </summary>
/// <returns>
/// <c>true</c> if users of this role are separated in the user list; otherwise <c>false</c>.
/// </returns>
bool IsHoisted { get; }
/// <summary> Returns true if this role is automatically managed by Discord. </summary>
/// <summary>
/// Gets a value that indicates whether the role is managed by Discord.
/// </summary>
/// <returns>
/// <c>true</c> if this role is automatically managed by Discord; otherwise <c>false</c>.
/// </returns>
bool IsManaged { get; }
/// <summary> Returns true if this role may be mentioned in messages. </summary>
/// <summary>
/// Gets a value that indicates whether the role is mentionable.
/// </summary>
/// <returns>
/// <c>true</c> if this role may be mentioned in messages; otherwise <c>false</c>.
/// </returns>
bool IsMentionable { get; }
/// <summary> Gets the name of this role. </summary>
/// <summary>
/// Gets the name of this role.
/// </summary>
/// <returns>
/// A string containing the name of this role.
/// </returns>
string Name { get; }
/// <summary> Gets the permissions granted to members of this role. </summary>
/// <summary>
/// Gets the permissions granted to members of this role.
/// </summary>
/// <returns>
/// A <see cref="GuildPermissions"/> struct that this role possesses.
/// </returns>
GuildPermissions Permissions { get; }
/// <summary> Gets this role's position relative to other roles in the same guild. </summary>
/// <summary>
/// Gets this role's position relative to other roles in the same guild.
/// </summary>
/// <returns>
/// An <see cref="int"/> representing the position of the role in the role list of the guild.
/// </returns>
int Position { get; }
///// <summary> Modifies this role. </summary>
/// <summary>
/// Modifies this role.
/// </summary>
/// <example>
/// <code language="cs">
/// await role.ModifyAsync(x =&gt;
/// {
/// x.Name = "Sonic";
/// x.Color = new Color(0x1A50BC);
/// x.Mentionable = true;
/// });
/// </code>
/// </example>
/// <param name="func">A delegate containing the properties to modify the role with.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous modification operation.
/// </returns>
Task ModifyAsync(Action<RoleProperties> func, RequestOptions options = null);
}
}

View File

@@ -1,12 +1,30 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Properties that are used to reorder an <see cref="IRole"/>.
/// </summary>
public class ReorderRoleProperties
{
/// <summary>The id of the role to be edited</summary>
/// <summary>
/// Gets the identifier of the role to be edited.
/// </summary>
/// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier of the role to be modified.
/// </returns>
public ulong Id { get; }
/// <summary>The new zero-based position of the role.</summary>
/// <summary>
/// Gets the new zero-based position of the role.
/// </summary>
/// <returns>
/// An <see cref="int"/> representing the new zero-based position of the role.
/// </returns>
public int Position { get; }
/// <summary>
/// Initializes a <see cref="ReorderRoleProperties" /> with the given role ID and position.
/// </summary>
/// <param name="id">The ID of the role to be edited.</param>
/// <param name="pos">The new zero-based position of the role.</param>
public ReorderRoleProperties(ulong id, int pos)
{
Id = id;

View File

@@ -1,57 +1,48 @@
namespace Discord
namespace Discord
{
/// <summary>
/// Modify an IRole with the specified parameters
/// Properties that are used to modify an <see cref="IRole" /> with the specified changes.
/// </summary>
/// <example>
/// <code language="c#">
/// await role.ModifyAsync(x =>
/// {
/// x.Color = new Color(180, 15, 40);
/// x.Hoist = true;
/// });
/// </code>
/// </example>
/// <seealso cref="IRole"/>
/// <seealso cref="IRole.ModifyAsync" />
public class RoleProperties
{
/// <summary>
/// The name of the role
/// Gets or sets the name of the role.
/// </summary>
/// <remarks>
/// If this role is the EveryoneRole, this value may not be set.
/// This value may not be set if the role is an @everyone role.
/// </remarks>
public Optional<string> Name { get; set; }
/// <summary>
/// The role's GuildPermissions
/// Gets or sets the role's <see cref="GuildPermission"/>.
/// </summary>
public Optional<GuildPermissions> Permissions { get; set; }
/// <summary>
/// The position of the role. This is 0-based!
/// Gets or sets the position of the role. This is 0-based!
/// </summary>
/// <remarks>
/// If this role is the EveryoneRole, this value may not be set.
/// This value may not be set if the role is an @everyone role.
/// </remarks>
public Optional<int> Position { get; set; }
/// <summary>
/// The color of the Role.
/// Gets or sets the color of the role.
/// </summary>
/// <remarks>
/// If this role is the EveryoneRole, this value may not be set.
/// This value may not be set if the role is an @everyone role.
/// </remarks>
public Optional<Color> Color { get; set; }
/// <summary>
/// Whether or not this role should be displayed independently in the userlist.
/// Gets or sets whether or not this role should be displayed independently in the user list.
/// </summary>
/// <remarks>
/// If this role is the EveryoneRole, this value may not be set.
/// This value may not be set if the role is an @everyone role.
/// </remarks>
public Optional<bool> Hoist { get; set; }
/// <summary>
/// Whether or not this role can be mentioned.
/// Gets or sets whether or not this role can be mentioned.
/// </summary>
/// <remarks>
/// If this role is the EveryoneRole, this value may not be set.
/// This value may not be set if the role is an @everyone role.
/// </remarks>
public Optional<bool> Mentionable { get; set; }
}

View File

@@ -1,70 +1,75 @@
using System.Collections.Generic;
using System.Collections.Generic;
namespace Discord
{
/// <summary>
/// Modify an IGuildUser with the following parameters.
/// Properties that are used to modify an <see cref="IGuildUser" /> with the following parameters.
/// </summary>
/// <example>
/// <code language="c#">
/// await (Context.User as IGuildUser)?.ModifyAsync(x =>
/// {
/// x.Nickname = $"festive {Context.User.Username}";
/// });
/// </code>
/// </example>
/// <seealso cref="IGuildUser"/>
/// <seealso cref="IGuildUser.ModifyAsync" />
public class GuildUserProperties
{
/// <summary>
/// Should the user be guild-muted in a voice channel?
/// Gets or sets whether the user should be muted in a voice channel.
/// </summary>
/// <remarks>
/// If this value is set to 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>
public Optional<bool> Mute { get; set; }
/// <summary>
/// Should the user be guild-deafened in a voice channel?
/// Gets or sets whether the user should be deafened in a voice channel.
/// </summary>
/// <remarks>
/// If this value is set to 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>
public Optional<bool> Deaf { get; set; }
/// <summary>
/// Should the user have a nickname set?
/// Gets or sets the user's nickname.
/// </summary>
/// <remarks>
/// To clear the user's nickname, this value can be set to <see langword="null" /> or <see cref="string.Empty" />.
/// To clear the user's nickname, this value can be set to <c>null</c> or
/// <see cref="string.Empty"/>.
/// </remarks>
public Optional<string> Nickname { get; set; }
/// <summary>
/// What roles should the user have?
/// Gets or sets the roles the user should have.
/// </summary>
/// <remarks>
/// To add a role to a user: <see cref="IGuildUser.AddRolesAsync(IEnumerable&lt;IRole&gt;, RequestOptions)"/>
/// To remove a role from a user: <see cref="IGuildUser.RemoveRolesAsync(IEnumerable&lt;IRole&gt;, RequestOptions)"/>
/// <para>
/// To add a role to a user:
/// <see cref="IGuildUser.AddRolesAsync(IEnumerable{IRole},RequestOptions)" />
/// </para>
/// <para>
/// To remove a role from a user:
/// <see cref="IGuildUser.RemoveRolesAsync(IEnumerable{IRole},RequestOptions)" />
/// </para>
/// </remarks>
public Optional<IEnumerable<IRole>> Roles { get; set; }
/// <summary>
/// What roles should the user have?
/// Gets or sets the roles the user should have.
/// </summary>
/// <remarks>
/// To add a role to a user: <see cref="IGuildUser.AddRolesAsync(IEnumerable&lt;IRole&gt;, RequestOptions)"/>
/// To remove a role from a user: <see cref="IGuildUser.RemoveRolesAsync(IEnumerable&lt;IRole&gt;, RequestOptions)"/>
/// <para>
/// To add a role to a user:
/// <see cref="IGuildUser.AddRolesAsync(IEnumerable{IRole},RequestOptions)" />
/// </para>
/// <para>
/// To remove a role from a user:
/// <see cref="IGuildUser.RemoveRolesAsync(IEnumerable{IRole},RequestOptions)" />
/// </para>
/// </remarks>
public Optional<IEnumerable<ulong>> RoleIds { get; set; }
/// <summary>
/// Move a user to a voice channel.
/// Moves a user to a voice channel.
/// </summary>
/// <remarks>
/// This user MUST already be in a Voice Channel for this to work.
/// This user MUST already be in a <see cref="IVoiceChannel"/> for this to work.
/// </remarks>
public Optional<IVoiceChannel> Channel { get; set; }
/// <summary>
/// Move a user to a voice channel.
/// Moves a user to a voice channel.
/// </summary>
/// <remarks>
/// This user MUST already be in a Voice Channel for this to work.
/// This user MUST already be in a <see cref="IVoiceChannel"/> for this to work.
/// </remarks>
public Optional<ulong> ChannelId { get; set; }
}

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