| @@ -1 +1,3 @@ | |||
| github: quinchs | |||
| open_collective: discordnet | |||
| custom: https://paypal.me/quinchs | |||
| @@ -1,5 +1,18 @@ | |||
| # Changelog | |||
| ## [3.6.1] - 2022-04-30 | |||
| ### Added | |||
| - #2272 add 50080 Error code (503e720) | |||
| ### Fixed | |||
| - #2267 Permissions v2 Invalid Operation Exception (a8f6075) | |||
| - #2271 null user on interaction without bot scope (f2bb55e) | |||
| - #2274 Implement fix for Custom Id Segments NRE (0d74c5c) | |||
| ### Misc | |||
| - 3.6.0 (27226f0) | |||
| ## [3.6.0] - 2022-04-28 | |||
| ### Added | |||
| - #2136 Passing CustomId matches into contexts (4ce1801) | |||
| @@ -1,6 +1,6 @@ | |||
| <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
| <PropertyGroup> | |||
| <VersionPrefix>3.6.0</VersionPrefix> | |||
| <VersionPrefix>3.6.1</VersionPrefix> | |||
| <LangVersion>latest</LangVersion> | |||
| <Authors>Discord.Net Contributors</Authors> | |||
| <PackageTags>discord;discordapp</PackageTags> | |||
| @@ -60,7 +60,7 @@ | |||
| "overwrite": "_overwrites/**/**.md", | |||
| "globalMetadata": { | |||
| "_appTitle": "Discord.Net Documentation", | |||
| "_appFooter": "Discord.Net (c) 2015-2022 3.6.0", | |||
| "_appFooter": "Discord.Net (c) 2015-2022 3.6.1", | |||
| "_enableSearch": true, | |||
| "_appLogoPath": "marketing/logo/SVG/Logomark Purple.svg", | |||
| "_appFaviconPath": "favicon.ico" | |||
| @@ -7,6 +7,8 @@ | |||
| <Description>A Discord.Net extension adding support for bot commands.</Description> | |||
| <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net6.0;net5.0;net461;netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">net6.0;net5.0;netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <WarningLevel>5</WarningLevel> | |||
| <TreatWarningsAsErrors>True</TreatWarningsAsErrors> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" /> | |||
| @@ -1,4 +1,4 @@ | |||
| using System; | |||
| using System; | |||
| namespace Discord.Commands | |||
| { | |||
| @@ -12,7 +12,7 @@ namespace Discord.Commands | |||
| /// <summary> | |||
| /// Gets on which pipeline stage the command may have matched or failed. | |||
| /// </summary> | |||
| public IResult? Pipeline { get; } | |||
| public IResult Pipeline { get; } | |||
| /// <inheritdoc /> | |||
| public CommandError? Error { get; } | |||
| @@ -21,7 +21,7 @@ namespace Discord.Commands | |||
| /// <inheritdoc /> | |||
| public bool IsSuccess => !Error.HasValue; | |||
| private MatchResult(CommandMatch? match, IResult? pipeline, CommandError? error, string errorReason) | |||
| private MatchResult(CommandMatch? match, IResult pipeline, CommandError? error, string errorReason) | |||
| { | |||
| Match = match; | |||
| Error = error; | |||
| @@ -7,6 +7,8 @@ | |||
| <Description>The core components for the Discord.Net library.</Description> | |||
| <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net6.0;net5.0;net461;netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">net6.0;net5.0;netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <WarningLevel>5</WarningLevel> | |||
| <TreatWarningsAsErrors>True</TreatWarningsAsErrors> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> | |||
| @@ -152,6 +152,7 @@ namespace Discord | |||
| InvalidMessageType = 50068, | |||
| PaymentSourceRequiredForGift = 50070, | |||
| CannotDeleteRequiredCommunityChannel = 50074, | |||
| CannotEditStickersWithinAMessage = 50080, | |||
| InvalidSticker = 50081, | |||
| CannotExecuteOnArchivedThread = 50083, | |||
| InvalidThreadNotificationSettings = 50084, | |||
| @@ -6,7 +6,7 @@ namespace Discord | |||
| /// <summary> | |||
| /// Represents a generic voice channel in a guild. | |||
| /// </summary> | |||
| public interface IVoiceChannel : INestedChannel, IAudioChannel, IMentionable | |||
| public interface IVoiceChannel : IMessageChannel, INestedChannel, IAudioChannel, IMentionable | |||
| { | |||
| /// <summary> | |||
| /// Gets the bit-rate that the clients in this voice channel are requested to use. | |||
| @@ -1173,7 +1173,6 @@ namespace Discord | |||
| /// in order to use this property. | |||
| /// </remarks> | |||
| /// </param> | |||
| /// <param name="speakers">A collection of speakers for the event.</param> | |||
| /// <param name="location">The location of the event; links are supported</param> | |||
| /// <param name="coverImage">The optional banner image for the event.</param> | |||
| /// <param name="options">The options to be used when sending the request.</param> | |||
| @@ -89,7 +89,7 @@ namespace Discord | |||
| /// Gets this events banner image url. | |||
| /// </summary> | |||
| /// <param name="format">The format to return.</param> | |||
| /// <param name="size">The size of the image to return in. This can be any power of two between 16 and 2048. | |||
| /// <param name="size">The size of the image to return in. This can be any power of two between 16 and 2048.</param> | |||
| /// <returns>The cover images url.</returns> | |||
| string GetCoverImageUrl(ImageFormat format = ImageFormat.Auto, ushort size = 1024); | |||
| @@ -56,7 +56,7 @@ namespace Discord | |||
| Number = 10, | |||
| /// <summary> | |||
| /// A <see cref="Discord.Attachment"/>. | |||
| /// A <see cref="IAttachment"/>. | |||
| /// </summary> | |||
| Attachment = 11 | |||
| } | |||
| @@ -55,7 +55,7 @@ namespace Discord | |||
| string UserLocale { get; } | |||
| /// <summary> | |||
| /// Gets the preferred locale of the guild this interaction was executed in. <see cref="null"/> if not executed in a guild. | |||
| /// Gets the preferred locale of the guild this interaction was executed in. <see langword="null"/> if not executed in a guild. | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// Non-community guilds (With no locale setting available) will have en-US as the default value sent by Discord. | |||
| @@ -1194,9 +1194,9 @@ namespace Discord | |||
| /// <summary> | |||
| /// Gets or sets the default value of the text input. | |||
| /// </summary> | |||
| /// <exception cref="ArgumentOutOfRangeException"><see cref="Value.Length"/> is less than 0.</exception> | |||
| /// <exception cref="ArgumentOutOfRangeException"><see cref="Value"/>.Length is less than 0.</exception> | |||
| /// <exception cref="ArgumentOutOfRangeException"> | |||
| /// <see cref="Value.Length"/> is greater than <see cref="LargestMaxLength"/> or <see cref="MaxLength"/>. | |||
| /// <see cref="Value"/>.Length is greater than <see cref="LargestMaxLength"/> or <see cref="MaxLength"/>. | |||
| /// </exception> | |||
| public string Value | |||
| { | |||
| @@ -1306,18 +1306,18 @@ namespace Discord | |||
| /// <summary> | |||
| /// Sets the minimum length of the current builder. | |||
| /// </summary> | |||
| /// <param name="placeholder">The value to set.</param> | |||
| /// <param name="minLength">The value to set.</param> | |||
| /// <returns>The current builder. </returns> | |||
| public TextInputBuilder WithMinLength(int minLength) | |||
| { | |||
| MinLength = minLength; | |||
| return this; | |||
| } | |||
| /// <summary> | |||
| /// Sets the maximum length of the current builder. | |||
| /// </summary> | |||
| /// <param name="placeholder">The value to set.</param> | |||
| /// <param name="maxLength">The value to set.</param> | |||
| /// <returns>The current builder. </returns> | |||
| public TextInputBuilder WithMaxLength(int maxLength) | |||
| { | |||
| @@ -64,18 +64,18 @@ namespace Discord | |||
| /// <summary> | |||
| /// Sets the custom id of the current modal. | |||
| /// </summary> | |||
| /// <param name="title">The value to set the custom id to.</param> | |||
| /// <param name="customId">The value to set the custom id to.</param> | |||
| /// <returns>The current builder.</returns> | |||
| public ModalBuilder WithCustomId(string customId) | |||
| { | |||
| CustomId = customId; | |||
| return this; | |||
| } | |||
| /// <summary> | |||
| /// Adds a component to the current builder. | |||
| /// </summary> | |||
| /// <param name="title">The component to add.</param> | |||
| /// <param name="component">The component to add.</param> | |||
| /// <returns>The current builder.</returns> | |||
| public ModalBuilder AddTextInput(TextInputBuilder component) | |||
| { | |||
| @@ -213,7 +213,7 @@ namespace Discord | |||
| /// Adds a <see cref="TextInputBuilder"/> to the <see cref="ModalComponentBuilder"/> at the specific row. | |||
| /// If the row cannot accept the component then it will add it to a row that can. | |||
| /// </summary> | |||
| /// <param name="text">The <see cref="TextInputBuilder"> to add.</param> | |||
| /// <param name="text">The <see cref="TextInputBuilder"/> to add.</param> | |||
| /// <param name="row">The row to add the text input.</param> | |||
| /// <exception cref="InvalidOperationException">There are no more rows to add a text input to.</exception> | |||
| /// <exception cref="ArgumentException"><paramref name="row"/> must be less than <see cref="MaxActionRowCount"/>.</exception> | |||
| @@ -27,6 +27,12 @@ namespace Discord | |||
| /// </summary> | |||
| public Optional<ulong> GuildId { get; internal set; } | |||
| /// <summary> | |||
| /// Gets whether to error if the referenced message doesn't exist instead of sending as a normal (non-reply) message | |||
| /// Defaults to true. | |||
| /// </summary> | |||
| public Optional<bool> FailIfNotExists { get; internal set; } | |||
| /// <summary> | |||
| /// Initializes a new instance of the <see cref="MessageReference"/> class. | |||
| /// </summary> | |||
| @@ -39,16 +45,21 @@ namespace Discord | |||
| /// <param name="guildId"> | |||
| /// The ID of the guild that will be referenced. It will be validated if sent. | |||
| /// </param> | |||
| public MessageReference(ulong? messageId = null, ulong? channelId = null, ulong? guildId = null) | |||
| /// <param name="failIfNotExists"> | |||
| /// Whether to error if the referenced message doesn't exist instead of sending as a normal (non-reply) message. Defaults to true. | |||
| /// </param> | |||
| public MessageReference(ulong? messageId = null, ulong? channelId = null, ulong? guildId = null, bool? failIfNotExists = null) | |||
| { | |||
| MessageId = messageId ?? Optional.Create<ulong>(); | |||
| InternalChannelId = channelId ?? Optional.Create<ulong>(); | |||
| GuildId = guildId ?? Optional.Create<ulong>(); | |||
| FailIfNotExists = failIfNotExists ?? Optional.Create<bool>(); | |||
| } | |||
| private string DebuggerDisplay | |||
| => $"Channel ID: ({ChannelId}){(GuildId.IsSpecified ? $", Guild ID: ({GuildId.Value})" : "")}" + | |||
| $"{(MessageId.IsSpecified ? $", Message ID: ({MessageId.Value})" : "")}"; | |||
| $"{(MessageId.IsSpecified ? $", Message ID: ({MessageId.Value})" : "")}" + | |||
| $"{(FailIfNotExists.IsSpecified ? $", FailIfNotExists: ({FailIfNotExists.Value})" : "")}"; | |||
| public override string ToString() | |||
| => DebuggerDisplay; | |||
| @@ -79,7 +79,7 @@ namespace Discord | |||
| /// Sets a timestamp how long a user should be timed out for. | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// <see cref="null"/> or a time in the past to clear a currently existing timeout. | |||
| /// <see langword="null"/> or a time in the past to clear a currently existing timeout. | |||
| /// </remarks> | |||
| public Optional<DateTimeOffset?> TimedOutUntil { get; set; } | |||
| } | |||
| @@ -104,7 +104,7 @@ namespace Discord | |||
| /// Gets the date and time that indicates if and for how long a user has been timed out. | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// <see cref="null"/> or a timestamp in the past if the user is not timed out. | |||
| /// <see langword="null"/> or a timestamp in the past if the user is not timed out. | |||
| /// </remarks> | |||
| /// <returns> | |||
| /// A <see cref="DateTimeOffset"/> indicating how long the user will be timed out for. | |||
| @@ -116,7 +116,7 @@ namespace Discord | |||
| /// </summary> | |||
| /// <example> | |||
| /// <para>The following example checks if the current user has the ability to send a message with attachment in | |||
| /// this channel; if so, uploads a file via <see cref="IMessageChannel.SendFileAsync(string, string, bool, Embed, RequestOptions, bool, AllowedMentions, MessageReference)"/>.</para> | |||
| /// this channel; if so, uploads a file via <see cref="IMessageChannel.SendFileAsync(string, string, bool, Embed, RequestOptions, bool, AllowedMentions, MessageReference, MessageComponent, ISticker[], Embed[], MessageFlags)"/>.</para> | |||
| /// <code language="cs"> | |||
| /// if (currentUser?.GetPermissions(targetChannel)?.AttachFiles) | |||
| /// await targetChannel.SendFileAsync("fortnite.png"); | |||
| @@ -151,7 +151,7 @@ namespace Discord | |||
| /// If the user does not have a guild avatar, this will be the user's regular avatar. | |||
| /// </remarks> | |||
| /// <param name="format">The format to return.</param> | |||
| /// <param name="size">The size of the image to return in. This can be any power of two between 16 and 2048. | |||
| /// <param name="size">The size of the image to return in. This can be any power of two between 16 and 2048.</param> | |||
| /// <returns> | |||
| /// A string representing the URL of the displayed avatar for this user. <see langword="null"/> if the user does not have an avatar in place. | |||
| /// </returns> | |||
| @@ -37,8 +37,9 @@ namespace Discord | |||
| /// <summary> Sanitizes the string, safely escaping any Markdown sequences. </summary> | |||
| public static string Sanitize(string text) | |||
| { | |||
| foreach (string unsafeChar in SensitiveCharacters) | |||
| text = text.Replace(unsafeChar, $"\\{unsafeChar}"); | |||
| if (text != null) | |||
| foreach (string unsafeChar in SensitiveCharacters) | |||
| text = text.Replace(unsafeChar, $"\\{unsafeChar}"); | |||
| return text; | |||
| } | |||
| @@ -23,7 +23,7 @@ namespace Discord.Utils | |||
| /// <summary> | |||
| /// Not full URL validation right now. Just Ensures the protocol is either http, https, or discord | |||
| /// <see cref="Validate(string)"/> should be used everything other than url buttons. | |||
| /// <see cref="Validate(string, bool)"/> should be used everything other than url buttons. | |||
| /// </summary> | |||
| /// <param name="url">The URL to validate before sending to discord.</param> | |||
| /// <exception cref="InvalidOperationException">A URL must include a protocol (either http, https, or discord).</exception> | |||
| @@ -3,7 +3,7 @@ using System; | |||
| namespace Discord.Interactions | |||
| { | |||
| /// <summary> | |||
| /// Set the <see cref="ApplicationCommandOptionProperties.Autocomplete"/> to <see langword="true"/>. | |||
| /// Set the <see cref="ApplicationCommandOptionProperties.IsAutocomplete"/> to <see langword="true"/>. | |||
| /// </summary> | |||
| [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] | |||
| public class AutocompleteAttribute : Attribute | |||
| @@ -14,7 +14,7 @@ namespace Discord.Interactions | |||
| public Type AutocompleteHandlerType { get; } | |||
| /// <summary> | |||
| /// Set the <see cref="ApplicationCommandOptionProperties.Autocomplete"/> to <see langword="true"/> and define a <see cref="AutocompleteHandler"/> to handle | |||
| /// Set the <see cref="ApplicationCommandOptionProperties.IsAutocomplete"/> to <see langword="true"/> and define a <see cref="AutocompleteHandler"/> to handle | |||
| /// Autocomplete interactions targeting the parameter this <see cref="Attribute"/> is applied to. | |||
| /// </summary> | |||
| /// <remarks> | |||
| @@ -29,7 +29,7 @@ namespace Discord.Interactions | |||
| } | |||
| /// <summary> | |||
| /// Set the <see cref="ApplicationCommandOptionProperties.Autocomplete"/> to <see langword="true"/> without specifying a <see cref="AutocompleteHandler"/>. | |||
| /// Set the <see cref="ApplicationCommandOptionProperties.IsAutocomplete"/> to <see langword="true"/> without specifying a <see cref="AutocompleteHandler"/>. | |||
| /// </summary> | |||
| public AutocompleteAttribute() { } | |||
| } | |||
| @@ -21,9 +21,7 @@ namespace Discord.Interactions | |||
| /// <summary> | |||
| /// Create a new <see cref="ModalInputAttribute"/>. | |||
| /// </summary> | |||
| /// <param name="label">The label of the input.</param> | |||
| /// <param name="customId">The custom id of the input.</param> | |||
| /// <param name="required">Whether the user is required to input a value.></param> | |||
| protected ModalInputAttribute(string customId) | |||
| { | |||
| CustomId = customId; | |||
| @@ -36,7 +36,7 @@ namespace Discord.Interactions | |||
| /// <summary> | |||
| /// Create a new <see cref="ModalTextInputAttribute"/>. | |||
| /// </summary> | |||
| /// <param name="customId"The custom id of the text input.></param> | |||
| /// <param name="customId">The custom id of the text input.></param> | |||
| /// <param name="style">The style of the text input.</param> | |||
| /// <param name="placeholder">The placeholder of the text input.</param> | |||
| /// <param name="minLength">The minimum length of the text input's content.</param> | |||
| @@ -29,7 +29,7 @@ namespace Discord.Interactions | |||
| /// <remarks> | |||
| /// This precondition will always fail if the command is being invoked in a <see cref="IPrivateChannel"/>. | |||
| /// </remarks> | |||
| /// <param name="permission"> | |||
| /// <param name="guildPermission"> | |||
| /// The <see cref="Discord.GuildPermission" /> that the user must have. Multiple permissions can be | |||
| /// specified by ORing the permissions together. | |||
| /// </param> | |||
| @@ -41,7 +41,7 @@ namespace Discord.Interactions | |||
| /// <summary> | |||
| /// Requires that the user invoking the command to have a specific <see cref="Discord.ChannelPermission"/>. | |||
| /// </summary> | |||
| /// <param name="permission"> | |||
| /// <param name="channelPermission"> | |||
| /// The <see cref="Discord.ChannelPermission"/> that the user must have. Multiple permissions can be | |||
| /// specified by ORing the permissions together. | |||
| /// </param> | |||
| @@ -56,7 +56,7 @@ namespace Discord.Interactions.Builders | |||
| /// <summary> | |||
| /// Sets <see cref="DefaultPermission"/>. | |||
| /// </summary> | |||
| /// <param name="defaultPermision">New value of the <see cref="DefaultPermission"/>.</param> | |||
| /// <param name="permission">New value of the <see cref="DefaultPermission"/>.</param> | |||
| /// <returns> | |||
| /// The builder instance. | |||
| /// </returns> | |||
| @@ -41,7 +41,7 @@ namespace Discord.Interactions.Builders | |||
| /// <summary> | |||
| /// Sets <see cref="Style"/>. | |||
| /// </summary> | |||
| /// <param name="style">New value of the <see cref="SetValue(string)"/>.</param> | |||
| /// <param name="style">New value of the <see cref="Style"/>.</param> | |||
| /// <returns> | |||
| /// The builder instance. | |||
| /// </returns> | |||
| @@ -64,7 +64,7 @@ namespace Discord.Interactions.Builders | |||
| } | |||
| /// <summary> | |||
| /// Adds text components to <see cref="TextComponents"/>. | |||
| /// Adds text components to <see cref="Components"/>. | |||
| /// </summary> | |||
| /// <param name="configure">Text Component builder factory.</param> | |||
| /// <returns> | |||
| @@ -357,7 +357,8 @@ namespace Discord.Interactions.Builders | |||
| return this; | |||
| } | |||
| /// <summary> | |||
| /// Adds a modal command builder to <see cref="ModalCommands"/>. | |||
| /// </summary> | |||
| /// <param name="configure"><see cref="ModalCommands"/> factory.</param> | |||
| @@ -122,7 +122,7 @@ namespace Discord.Interactions.Builders | |||
| /// <summary> | |||
| /// Adds preconditions to <see cref="Preconditions"/> | |||
| /// </summary> | |||
| /// <param name="preconditions">New attributes to be added to <see cref="Preconditions"/>.</param> | |||
| /// <param name="attributes">New attributes to be added to <see cref="Preconditions"/>.</param> | |||
| /// <returns> | |||
| /// The builder instance. | |||
| /// </returns> | |||
| @@ -7,8 +7,10 @@ | |||
| <RootNamespace>Discord.Interactions</RootNamespace> | |||
| <AssemblyName>Discord.Net.Interactions</AssemblyName> | |||
| <Description>A Discord.Net extension adding support for Application Commands.</Description> | |||
| <WarningLevel>5</WarningLevel> | |||
| <TreatWarningsAsErrors>True</TreatWarningsAsErrors> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" /> | |||
| <ProjectReference Include="..\Discord.Net.Rest\Discord.Net.Rest.csproj" /> | |||
| @@ -24,8 +24,7 @@ namespace Discord.Interactions | |||
| /// </summary> | |||
| /// <param name="client">The underlying client.</param> | |||
| /// <param name="interaction">The underlying interaction.</param> | |||
| /// <param name="user"><see cref="IUser"/> who executed the command.</param> | |||
| /// <param name="channel"><see cref="ISocketMessageChannel"/> the command originated from.</param> | |||
| /// <param name="channel"><see cref="IMessageChannel"/> the command originated from.</param> | |||
| public InteractionContext(IDiscordClient client, IDiscordInteraction interaction, IMessageChannel channel = null) | |||
| { | |||
| Client = client; | |||
| @@ -45,7 +45,7 @@ namespace Discord.Interactions | |||
| protected virtual async Task DeferAsync(bool ephemeral = false, RequestOptions options = null) => | |||
| await Context.Interaction.DeferAsync(ephemeral, options).ConfigureAwait(false); | |||
| /// <inheritdoc cref="IDiscordInteraction.RespondAsync(string, Embed[], bool, bool, AllowedMentions, RequestOptions, MessageComponent, Embed)"/> | |||
| /// <inheritdoc cref="IDiscordInteraction.RespondAsync(string, Embed[], bool, bool, AllowedMentions, MessageComponent, Embed, RequestOptions)"/> | |||
| protected virtual async Task RespondAsync (string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, | |||
| AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent components = null, Embed embed = null) => | |||
| await Context.Interaction.RespondAsync(text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options).ConfigureAwait(false); | |||
| @@ -70,7 +70,7 @@ namespace Discord.Interactions | |||
| AllowedMentions allowedMentions = null, MessageComponent components = null, Embed embed = null, RequestOptions options = null) | |||
| => Context.Interaction.RespondWithFilesAsync(attachments, text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options); | |||
| /// <inheritdoc cref="IDiscordInteraction.FollowupAsync(string, Embed[], bool, bool, AllowedMentions, RequestOptions, MessageComponent, Embed)"/> | |||
| /// <inheritdoc cref="IDiscordInteraction.FollowupAsync(string, Embed[], bool, bool, AllowedMentions, MessageComponent, Embed, RequestOptions)"/> | |||
| protected virtual async Task<IUserMessage> FollowupAsync (string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, | |||
| AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent components = null, Embed embed = null) => | |||
| await Context.Interaction.FollowupAsync(text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options).ConfigureAwait(false); | |||
| @@ -95,7 +95,7 @@ namespace Discord.Interactions | |||
| AllowedMentions allowedMentions = null, MessageComponent components = null, Embed embed = null, RequestOptions options = null) | |||
| => Context.Interaction.FollowupWithFilesAsync(attachments, text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options); | |||
| /// <inheritdoc cref="IMessageChannel.SendMessageAsync(string, bool, Embed, RequestOptions, AllowedMentions, MessageReference, MessageComponent, ISticker[], Embed[])"/> | |||
| /// <inheritdoc cref="IMessageChannel.SendMessageAsync(string, bool, Embed, RequestOptions, AllowedMentions, MessageReference, MessageComponent, ISticker[], Embed[], MessageFlags)"/> | |||
| protected virtual async Task<IUserMessage> ReplyAsync (string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, | |||
| AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null) => | |||
| await Context.Channel.SendMessageAsync(text, false, embed, options, allowedMentions, messageReference, components).ConfigureAwait(false); | |||
| @@ -118,9 +118,9 @@ namespace Discord.Interactions | |||
| /// <inheritdoc cref="IDiscordInteraction.RespondWithModalAsync(Modal, RequestOptions)"/> | |||
| protected virtual async Task RespondWithModalAsync(Modal modal, RequestOptions options = null) => await Context.Interaction.RespondWithModalAsync(modal); | |||
| /// <inheritdoc cref="IDiscordInteractionExtentions.RespondWithModalAsync(IDiscordInteraction, IModal, RequestOptions)"/> | |||
| protected virtual async Task RespondWithModalAsync<T>(string customId, RequestOptions options = null) where T : class, IModal | |||
| => await Context.Interaction.RespondWithModalAsync<T>(customId, options); | |||
| /// <inheritdoc cref="IDiscordInteractionExtentions.RespondWithModalAsync{T}(IDiscordInteraction, string, RequestOptions, Action{ModalBuilder})"/> | |||
| protected virtual async Task RespondWithModalAsync<TModal>(string customId, RequestOptions options = null) where TModal : class, IModal | |||
| => await Context.Interaction.RespondWithModalAsync<TModal>(customId, options); | |||
| //IInteractionModuleBase | |||
| @@ -421,7 +421,7 @@ namespace Discord.Interactions | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// Commands will be registered as standalone commands, if you want the <see cref="GroupAttribute"/> to take effect, | |||
| /// use <see cref="AddModulesToGuildAsync(IGuild, ModuleInfo[])"/>. Registering a commands without group names might cause the command traversal to fail. | |||
| /// use <see cref="AddModulesToGuildAsync(IGuild, bool, ModuleInfo[])"/>. Registering a commands without group names might cause the command traversal to fail. | |||
| /// </remarks> | |||
| /// <param name="guild">The target guild.</param> | |||
| /// <param name="commands">Commands to be registered to Discord.</param> | |||
| @@ -517,7 +517,7 @@ namespace Discord.Interactions | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// Commands will be registered as standalone commands, if you want the <see cref="GroupAttribute"/> to take effect, | |||
| /// use <see cref="AddModulesToGuildAsync(IGuild, ModuleInfo[])"/>. Registering a commands without group names might cause the command traversal to fail. | |||
| /// use <see cref="AddModulesToGuildAsync(IGuild, bool, ModuleInfo[])"/>. Registering a commands without group names might cause the command traversal to fail. | |||
| /// </remarks> | |||
| /// <param name="commands">Commands to be registered to Discord.</param> | |||
| /// <returns> | |||
| @@ -834,11 +834,16 @@ namespace Discord.Interactions | |||
| if (!searchResult.Command.SupportsWildCards || context is not IRouteMatchContainer matchContainer) | |||
| return; | |||
| var matches = new RouteSegmentMatch[searchResult.RegexCaptureGroups.Length]; | |||
| for (var i = 0; i < searchResult.RegexCaptureGroups.Length; i++) | |||
| matches[i] = new RouteSegmentMatch(searchResult.RegexCaptureGroups[i]); | |||
| if (searchResult.RegexCaptureGroups?.Length > 0) | |||
| { | |||
| var matches = new RouteSegmentMatch[searchResult.RegexCaptureGroups.Length]; | |||
| for (var i = 0; i < searchResult.RegexCaptureGroups.Length; i++) | |||
| matches[i] = new RouteSegmentMatch(searchResult.RegexCaptureGroups[i]); | |||
| matchContainer.SetSegmentMatches(matches); | |||
| matchContainer.SetSegmentMatches(matches); | |||
| } | |||
| else | |||
| matchContainer.SetSegmentMatches(Array.Empty<RouteSegmentMatch>()); | |||
| } | |||
| internal TypeConverter GetTypeConverter(Type type, IServiceProvider services = null) | |||
| @@ -960,7 +965,7 @@ namespace Discord.Interactions | |||
| /// Removes a type reader for the given type. | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// Removing a <see cref="TypeReader"/> from the <see cref="CommandService"/> will not dereference the <see cref="TypeReader"/> from the loaded module/command instances. | |||
| /// Removing a <see cref="TypeReader"/> from the <see cref="InteractionService"/> will not dereference the <see cref="TypeReader"/> from the loaded module/command instances. | |||
| /// You need to reload the modules for the changes to take effect. | |||
| /// </remarks> | |||
| /// <param name="type">The type to remove the reader from.</param> | |||
| @@ -973,7 +978,7 @@ namespace Discord.Interactions | |||
| /// Removes a generic type reader from the type <typeparamref name="T"/>. | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// Removing a <see cref="TypeReader"/> from the <see cref="CommandService"/> will not dereference the <see cref="TypeReader"/> from the loaded module/command instances. | |||
| /// Removing a <see cref="TypeReader"/> from the <see cref="InteractionService"/> will not dereference the <see cref="TypeReader"/> from the loaded module/command instances. | |||
| /// You need to reload the modules for the changes to take effect. | |||
| /// </remarks> | |||
| /// <typeparam name="T">The type to remove the readers from.</typeparam> | |||
| @@ -986,7 +991,7 @@ namespace Discord.Interactions | |||
| /// Removes a generic type reader from the given type. | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// Removing a <see cref="TypeReader"/> from the <see cref="CommandService"/> will not dereference the <see cref="TypeReader"/> from the loaded module/command instances. | |||
| /// Removing a <see cref="TypeReader"/> from the <see cref="InteractionService"/> will not dereference the <see cref="TypeReader"/> from the loaded module/command instances. | |||
| /// You need to reload the modules for the changes to take effect. | |||
| /// </remarks> | |||
| /// <param name="type">The type to remove the reader from.</param> | |||
| @@ -999,7 +1004,7 @@ namespace Discord.Interactions | |||
| /// Serialize an object using a <see cref="TypeReader"/> into a <see cref="string"/> to be placed in a Component CustomId. | |||
| /// </summary> | |||
| /// <remarks> | |||
| /// Removing a <see cref="TypeReader"/> from the <see cref="CommandService"/> will not dereference the <see cref="TypeReader"/> from the loaded module/command instances. | |||
| /// Removing a <see cref="TypeReader"/> from the <see cref="InteractionService"/> will not dereference the <see cref="TypeReader"/> from the loaded module/command instances. | |||
| /// You need to reload the modules for the changes to take effect. | |||
| /// </remarks> | |||
| /// <typeparam name="T">Type of the object to be serialized.</typeparam> | |||
| @@ -87,12 +87,12 @@ namespace Discord.Interactions | |||
| await InteractionService._restResponseCallback(Context, payload).ConfigureAwait(false); | |||
| } | |||
| protected override async Task RespondWithModalAsync<T>(string customId, RequestOptions options = null) | |||
| protected override async Task RespondWithModalAsync<TModal>(string customId, RequestOptions options = null) | |||
| { | |||
| if (Context.Interaction is not RestInteraction restInteraction) | |||
| throw new InvalidOperationException($"Invalid interaction type. Interaction must be a type of {nameof(RestInteraction)} in order to execute this method"); | |||
| var payload = restInteraction.RespondWithModal<T>(customId, options); | |||
| var payload = restInteraction.RespondWithModal<TModal>(customId, options); | |||
| if (Context is IRestInteractionContext restContext && restContext.InteractionResponseCallback != null) | |||
| await restContext.InteractionResponseCallback.Invoke(payload).ConfigureAwait(false); | |||
| @@ -3,7 +3,7 @@ using System; | |||
| namespace Discord.Interactions | |||
| { | |||
| /// <summary> | |||
| /// Represents a result type for <see cref="TypeConverter.ReadAsync(IInteractionContext, WebSocket.SocketSlashCommandDataOption, IServiceProvider)"/>. | |||
| /// Represents a result type for <see cref="TypeConverter.ReadAsync(IInteractionContext, IApplicationCommandInteractionDataOption, IServiceProvider)"/>. | |||
| /// </summary> | |||
| public struct TypeConverterResult : IResult | |||
| { | |||
| @@ -12,5 +12,8 @@ namespace Discord.API | |||
| [JsonProperty("guild_id")] | |||
| public Optional<ulong> GuildId { get; set; } | |||
| [JsonProperty("fail_if_not_exists")] | |||
| public Optional<bool> FailIfNotExists { get; set; } | |||
| } | |||
| } | |||
| @@ -7,6 +7,8 @@ | |||
| <Description>A core Discord.Net library containing the REST client and models.</Description> | |||
| <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net6.0;net5.0;net461;netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">net6.0;net5.0;netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <WarningLevel>5</WarningLevel> | |||
| <TreatWarningsAsErrors>True</TreatWarningsAsErrors> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" /> | |||
| @@ -173,10 +173,12 @@ namespace Discord.API | |||
| private async Task LogoutInternalAsync() | |||
| { | |||
| //An exception here will lock the client into the unusable LoggingOut state, but that's probably fine since our client is in an undefined state too. | |||
| if (LoginState == LoginState.LoggedOut) return; | |||
| if (LoginState == LoginState.LoggedOut) | |||
| return; | |||
| LoginState = LoginState.LoggingOut; | |||
| try { _loginCancelToken?.Cancel(false); } | |||
| try | |||
| { _loginCancelToken?.Cancel(false); } | |||
| catch { } | |||
| await DisconnectInternalAsync(null).ConfigureAwait(false); | |||
| @@ -398,7 +400,7 @@ namespace Discord.API | |||
| Preconditions.AtLeast(args.Position, 0, nameof(args.Position)); | |||
| Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name)); | |||
| if(args.Name.IsSpecified) | |||
| if (args.Name.IsSpecified) | |||
| Preconditions.AtMost(args.Name.Value.Length, 100, nameof(args.Name)); | |||
| options = RequestOptions.CreateOrClone(options); | |||
| @@ -414,9 +416,9 @@ namespace Discord.API | |||
| Preconditions.AtLeast(args.Position, 0, nameof(args.Position)); | |||
| Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name)); | |||
| if(args.Name.IsSpecified) | |||
| if (args.Name.IsSpecified) | |||
| Preconditions.AtMost(args.Name.Value.Length, 100, nameof(args.Name)); | |||
| if(args.Topic.IsSpecified) | |||
| if (args.Topic.IsSpecified) | |||
| Preconditions.AtMost(args.Topic.Value.Length, 1024, nameof(args.Name)); | |||
| Preconditions.AtLeast(args.SlowModeInterval, 0, nameof(args.SlowModeInterval)); | |||
| @@ -798,9 +800,11 @@ namespace Discord.API | |||
| var ids = new BucketIds(channelId: channelId); | |||
| return await SendJsonAsync<Message>("POST", () => $"channels/{channelId}/messages", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | |||
| } | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="InvalidOperationException">This operation may only be called with a <see cref="TokenType.Webhook"/> token.</exception> | |||
| public async Task<Message> CreateWebhookMessageAsync(ulong webhookId, CreateWebhookMessageParams args, RequestOptions options = null) | |||
| public async Task<Message> CreateWebhookMessageAsync(ulong webhookId, CreateWebhookMessageParams args, RequestOptions options = null, ulong? threadId = null) | |||
| { | |||
| if (AuthTokenType != TokenType.Webhook) | |||
| throw new InvalidOperationException($"This operation may only be called with a {nameof(TokenType.Webhook)} token."); | |||
| @@ -816,12 +820,12 @@ namespace Discord.API | |||
| options = RequestOptions.CreateOrClone(options); | |||
| var ids = new BucketIds(webhookId: webhookId); | |||
| return await SendJsonAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?wait=true", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | |||
| return await SendJsonAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?{WebhookQuery(true, threadId)}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | |||
| } | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="InvalidOperationException">This operation may only be called with a <see cref="TokenType.Webhook"/> token.</exception> | |||
| public async Task ModifyWebhookMessageAsync(ulong webhookId, ulong messageId, ModifyWebhookMessageParams args, RequestOptions options = null) | |||
| public async Task ModifyWebhookMessageAsync(ulong webhookId, ulong messageId, ModifyWebhookMessageParams args, RequestOptions options = null, ulong? threadId = null) | |||
| { | |||
| if (AuthTokenType != TokenType.Webhook) | |||
| throw new InvalidOperationException($"This operation may only be called with a {nameof(TokenType.Webhook)} token."); | |||
| @@ -837,11 +841,11 @@ namespace Discord.API | |||
| options = RequestOptions.CreateOrClone(options); | |||
| var ids = new BucketIds(webhookId: webhookId); | |||
| await SendJsonAsync<Message>("PATCH", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | |||
| await SendJsonAsync<Message>("PATCH", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}${WebhookQuery(false, threadId)}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | |||
| } | |||
| /// <exception cref="InvalidOperationException">This operation may only be called with a <see cref="TokenType.Webhook"/> token.</exception> | |||
| public async Task DeleteWebhookMessageAsync(ulong webhookId, ulong messageId, RequestOptions options = null) | |||
| public async Task DeleteWebhookMessageAsync(ulong webhookId, ulong messageId, RequestOptions options = null, ulong? threadId = null) | |||
| { | |||
| if (AuthTokenType != TokenType.Webhook) | |||
| throw new InvalidOperationException($"This operation may only be called with a {nameof(TokenType.Webhook)} token."); | |||
| @@ -852,7 +856,7 @@ namespace Discord.API | |||
| options = RequestOptions.CreateOrClone(options); | |||
| var ids = new BucketIds(webhookId: webhookId); | |||
| await SendAsync("DELETE", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}", ids, options: options).ConfigureAwait(false); | |||
| await SendAsync("DELETE", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}?{WebhookQuery(false, threadId)}", ids, options: options).ConfigureAwait(false); | |||
| } | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| @@ -873,7 +877,7 @@ namespace Discord.API | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="InvalidOperationException">This operation may only be called with a <see cref="TokenType.Webhook"/> token.</exception> | |||
| public async Task<Message> UploadWebhookFileAsync(ulong webhookId, UploadWebhookFileParams args, RequestOptions options = null) | |||
| public async Task<Message> UploadWebhookFileAsync(ulong webhookId, UploadWebhookFileParams args, RequestOptions options = null, ulong? threadId = null) | |||
| { | |||
| if (AuthTokenType != TokenType.Webhook) | |||
| throw new InvalidOperationException($"This operation may only be called with a {nameof(TokenType.Webhook)} token."); | |||
| @@ -893,7 +897,7 @@ namespace Discord.API | |||
| } | |||
| var ids = new BucketIds(webhookId: webhookId); | |||
| return await SendMultipartAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?wait=true", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | |||
| return await SendMultipartAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?{WebhookQuery(true, threadId)}", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task DeleteMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null) | |||
| { | |||
| @@ -1380,7 +1384,7 @@ namespace Discord.API | |||
| if ((!args.Embeds.IsSpecified || args.Embeds.Value == null || args.Embeds.Value.Length == 0) && !args.File.IsSpecified) | |||
| Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content)); | |||
| if(args.Content.IsSpecified && args.Content.Value?.Length > DiscordConfig.MaxMessageSize) | |||
| if (args.Content.IsSpecified && args.Content.Value?.Length > DiscordConfig.MaxMessageSize) | |||
| throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content)); | |||
| options = RequestOptions.CreateOrClone(options); | |||
| @@ -1400,7 +1404,7 @@ namespace Discord.API | |||
| throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content)); | |||
| options = RequestOptions.CreateOrClone(options); | |||
| var ids = new BucketIds(); | |||
| return await SendMultipartAsync<Message>("POST", () => $"webhooks/{CurrentApplicationId}/{token}?wait=true", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | |||
| } | |||
| @@ -1729,8 +1733,10 @@ namespace Discord.API | |||
| if (args.TargetType.IsSpecified) | |||
| { | |||
| Preconditions.NotEqual((int)args.TargetType.Value, (int)TargetUserType.Undefined, nameof(args.TargetType)); | |||
| if (args.TargetType.Value == TargetUserType.Stream) Preconditions.GreaterThan(args.TargetUserId, 0, nameof(args.TargetUserId)); | |||
| if (args.TargetType.Value == TargetUserType.EmbeddedApplication) Preconditions.GreaterThan(args.TargetApplicationId, 0, nameof(args.TargetUserId)); | |||
| if (args.TargetType.Value == TargetUserType.Stream) | |||
| Preconditions.GreaterThan(args.TargetUserId, 0, nameof(args.TargetUserId)); | |||
| if (args.TargetType.Value == TargetUserType.EmbeddedApplication) | |||
| Preconditions.GreaterThan(args.TargetApplicationId, 0, nameof(args.TargetUserId)); | |||
| } | |||
| options = RequestOptions.CreateOrClone(options); | |||
| @@ -2414,6 +2420,18 @@ namespace Discord.API | |||
| return (expr as MemberExpression).Member.Name; | |||
| } | |||
| private static string WebhookQuery(bool wait = false, ulong? threadId = null) | |||
| { | |||
| List<string> querys = new List<string>() { }; | |||
| if (wait) | |||
| querys.Add("wait=true"); | |||
| if (threadId.HasValue) | |||
| querys.Add($"thread_id={threadId}"); | |||
| return $"{string.Join("&", querys)}"; | |||
| } | |||
| #endregion | |||
| } | |||
| } | |||
| @@ -12,7 +12,11 @@ namespace Discord.Rest | |||
| public class RestStageChannel : RestVoiceChannel, IStageChannel | |||
| { | |||
| /// <inheritdoc/> | |||
| public string Topic { get; private set; } | |||
| /// <remarks> | |||
| /// This field is always false for stage channels. | |||
| /// </remarks> | |||
| public override bool IsTextInVoice | |||
| => false; | |||
| /// <inheritdoc/> | |||
| public StagePrivacyLevel? PrivacyLevel { get; private set; } | |||
| @@ -37,13 +41,11 @@ namespace Discord.Rest | |||
| IsLive = isLive; | |||
| if(isLive) | |||
| { | |||
| Topic = model.Topic; | |||
| PrivacyLevel = model.PrivacyLevel; | |||
| IsDiscoverableDisabled = model.DiscoverableDisabled; | |||
| } | |||
| else | |||
| { | |||
| Topic = null; | |||
| PrivacyLevel = null; | |||
| IsDiscoverableDisabled = null; | |||
| } | |||
| @@ -86,25 +86,25 @@ namespace Discord.Rest | |||
| => ChannelHelper.GetUsersAsync(this, Guild, Discord, null, null, options); | |||
| /// <inheritdoc /> | |||
| public Task<RestMessage> GetMessageAsync(ulong id, RequestOptions options = null) | |||
| public virtual Task<RestMessage> GetMessageAsync(ulong id, RequestOptions options = null) | |||
| => ChannelHelper.GetMessageAsync(this, Discord, id, options); | |||
| /// <inheritdoc /> | |||
| public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| public virtual IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => ChannelHelper.GetMessagesAsync(this, Discord, null, Direction.Before, limit, options); | |||
| /// <inheritdoc /> | |||
| public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| public virtual IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => ChannelHelper.GetMessagesAsync(this, Discord, fromMessageId, dir, limit, options); | |||
| /// <inheritdoc /> | |||
| public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| public virtual IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => ChannelHelper.GetMessagesAsync(this, Discord, fromMessage.Id, dir, limit, options); | |||
| /// <inheritdoc /> | |||
| public Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(RequestOptions options = null) | |||
| public virtual Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(RequestOptions options = null) | |||
| => ChannelHelper.GetPinnedMessagesAsync(this, Discord, options); | |||
| /// <inheritdoc /> | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="ArgumentException">The only valid <see cref="MessageFlags"/> are <see cref="MessageFlags.SuppressEmbeds"/> and <see cref="MessageFlags.None"/>.</exception> | |||
| public Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, | |||
| public virtual Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, | |||
| RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, | |||
| MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, | |||
| @@ -136,7 +136,7 @@ namespace Discord.Rest | |||
| /// <exception cref="IOException">An I/O error occurred while opening the file.</exception> | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="ArgumentException">The only valid <see cref="MessageFlags"/> are <see cref="MessageFlags.SuppressEmbeds"/> and <see cref="MessageFlags.None"/>.</exception> | |||
| public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, | |||
| public virtual Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, | |||
| RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, | |||
| MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, | |||
| Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| @@ -146,7 +146,7 @@ namespace Discord.Rest | |||
| /// <inheritdoc /> | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="ArgumentException">The only valid <see cref="MessageFlags"/> are <see cref="MessageFlags.SuppressEmbeds"/> and <see cref="MessageFlags.None"/>.</exception> | |||
| public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, | |||
| public virtual Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, | |||
| Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, | |||
| MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, | |||
| Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| @@ -156,7 +156,7 @@ namespace Discord.Rest | |||
| /// <inheritdoc /> | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="ArgumentException">The only valid <see cref="MessageFlags"/> are <see cref="MessageFlags.SuppressEmbeds"/> and <see cref="MessageFlags.None"/>.</exception> | |||
| public Task<RestUserMessage> SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, | |||
| public virtual Task<RestUserMessage> SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, | |||
| Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | |||
| MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, | |||
| Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| @@ -166,35 +166,35 @@ namespace Discord.Rest | |||
| /// <inheritdoc /> | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="ArgumentException">The only valid <see cref="MessageFlags"/> are <see cref="MessageFlags.SuppressEmbeds"/> and <see cref="MessageFlags.None"/>.</exception> | |||
| public Task<RestUserMessage> SendFilesAsync(IEnumerable<FileAttachment> attachments, string text, bool isTTS = false, | |||
| public virtual Task<RestUserMessage> SendFilesAsync(IEnumerable<FileAttachment> attachments, string text, bool isTTS = false, | |||
| Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | |||
| MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, | |||
| Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| => ChannelHelper.SendFilesAsync(this, Discord, attachments, text, isTTS, embed, allowedMentions, messageReference, components, stickers, options, embeds, flags); | |||
| /// <inheritdoc /> | |||
| public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) | |||
| public virtual Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) | |||
| => ChannelHelper.DeleteMessageAsync(this, messageId, Discord, options); | |||
| /// <inheritdoc /> | |||
| public Task DeleteMessageAsync(IMessage message, RequestOptions options = null) | |||
| public virtual Task DeleteMessageAsync(IMessage message, RequestOptions options = null) | |||
| => ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options); | |||
| /// <inheritdoc /> | |||
| public Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null) | |||
| public virtual Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null) | |||
| => ChannelHelper.DeleteMessagesAsync(this, Discord, messages.Select(x => x.Id), options); | |||
| /// <inheritdoc /> | |||
| public Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null) | |||
| public virtual Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null) | |||
| => ChannelHelper.DeleteMessagesAsync(this, Discord, messageIds, options); | |||
| /// <inheritdoc /> | |||
| public async Task<IUserMessage> ModifyMessageAsync(ulong messageId, Action<MessageProperties> func, RequestOptions options = null) | |||
| public virtual async Task<IUserMessage> ModifyMessageAsync(ulong messageId, Action<MessageProperties> func, RequestOptions options = null) | |||
| => await ChannelHelper.ModifyMessageAsync(this, messageId, func, Discord, options).ConfigureAwait(false); | |||
| /// <inheritdoc /> | |||
| public Task TriggerTypingAsync(RequestOptions options = null) | |||
| public virtual Task TriggerTypingAsync(RequestOptions options = null) | |||
| => ChannelHelper.TriggerTypingAsync(this, Discord, options); | |||
| /// <inheritdoc /> | |||
| public IDisposable EnterTypingState(RequestOptions options = null) | |||
| public virtual IDisposable EnterTypingState(RequestOptions options = null) | |||
| => ChannelHelper.EnterTypingState(this, Discord, options); | |||
| /// <summary> | |||
| @@ -231,38 +231,6 @@ namespace Discord.Rest | |||
| public virtual Task<IReadOnlyCollection<RestWebhook>> GetWebhooksAsync(RequestOptions options = null) | |||
| => ChannelHelper.GetWebhooksAsync(this, Discord, options); | |||
| /// <summary> | |||
| /// Gets the parent (category) channel of 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. The task result contains the category channel | |||
| /// representing the parent of this channel; <c>null</c> if none is set. | |||
| /// </returns> | |||
| public virtual Task<ICategoryChannel> GetCategoryAsync(RequestOptions options = null) | |||
| => ChannelHelper.GetCategoryAsync(this, Discord, options); | |||
| /// <inheritdoc /> | |||
| public Task SyncPermissionsAsync(RequestOptions options = null) | |||
| => ChannelHelper.SyncPermissionsAsync(this, Discord, options); | |||
| #endregion | |||
| #region Invites | |||
| /// <inheritdoc /> | |||
| public virtual async Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); | |||
| public virtual async Task<IInviteMetadata> CreateInviteToApplicationAsync(ulong applicationId, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options); | |||
| /// <inheritdoc /> | |||
| public virtual async Task<IInviteMetadata> CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, (ulong)application, options); | |||
| public virtual Task<IInviteMetadata> CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => throw new NotImplementedException(); | |||
| /// <inheritdoc /> | |||
| public virtual async Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | |||
| => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); | |||
| private string DebuggerDisplay => $"{Name} ({Id}, Text)"; | |||
| /// <summary> | |||
| /// Creates a thread within this <see cref="ITextChannel"/>. | |||
| /// </summary> | |||
| @@ -299,6 +267,38 @@ namespace Discord.Rest | |||
| var model = await ThreadHelper.CreateThreadAsync(Discord, this, name, type, autoArchiveDuration, message, invitable, slowmode, options); | |||
| return RestThreadChannel.Create(Discord, Guild, model); | |||
| } | |||
| /// <summary> | |||
| /// Gets the parent (category) channel of 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. The task result contains the category channel | |||
| /// representing the parent of this channel; <c>null</c> if none is set. | |||
| /// </returns> | |||
| public virtual Task<ICategoryChannel> GetCategoryAsync(RequestOptions options = null) | |||
| => ChannelHelper.GetCategoryAsync(this, Discord, options); | |||
| /// <inheritdoc /> | |||
| public Task SyncPermissionsAsync(RequestOptions options = null) | |||
| => ChannelHelper.SyncPermissionsAsync(this, Discord, options); | |||
| #endregion | |||
| #region Invites | |||
| /// <inheritdoc /> | |||
| public virtual async Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); | |||
| public virtual async Task<IInviteMetadata> CreateInviteToApplicationAsync(ulong applicationId, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options); | |||
| /// <inheritdoc /> | |||
| public virtual async Task<IInviteMetadata> CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, (ulong)application, options); | |||
| public virtual Task<IInviteMetadata> CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => throw new NotImplementedException(); | |||
| /// <inheritdoc /> | |||
| public virtual async Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | |||
| => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); | |||
| private string DebuggerDisplay => $"{Name} ({Id}, Text)"; | |||
| #endregion | |||
| #region ITextChannel | |||
| @@ -2,6 +2,7 @@ using Discord.Audio; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Diagnostics; | |||
| using System.IO; | |||
| using System.Linq; | |||
| using System.Threading.Tasks; | |||
| using Model = Discord.API.Channel; | |||
| @@ -12,21 +13,21 @@ namespace Discord.Rest | |||
| /// Represents a REST-based voice channel in a guild. | |||
| /// </summary> | |||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
| public class RestVoiceChannel : RestGuildChannel, IVoiceChannel, IRestAudioChannel | |||
| public class RestVoiceChannel : RestTextChannel, IVoiceChannel, IRestAudioChannel | |||
| { | |||
| #region RestVoiceChannel | |||
| /// <summary> | |||
| /// Gets whether or not the guild has Text-In-Voice enabled and the voice channel is a TiV channel. | |||
| /// </summary> | |||
| public virtual bool IsTextInVoice | |||
| => Guild.Features.HasTextInVoice; | |||
| /// <inheritdoc /> | |||
| public int Bitrate { get; private set; } | |||
| /// <inheritdoc /> | |||
| public int? UserLimit { get; private set; } | |||
| /// <inheritdoc /> | |||
| public ulong? CategoryId { get; private set; } | |||
| /// <inheritdoc/> | |||
| public string RTCRegion { get; private set; } | |||
| /// <inheritdoc /> | |||
| public string Mention => MentionUtils.MentionChannel(Id); | |||
| internal RestVoiceChannel(BaseDiscordClient discord, IGuild guild, ulong id) | |||
| : base(discord, guild, id) | |||
| { | |||
| @@ -41,7 +42,6 @@ namespace Discord.Rest | |||
| internal override void Update(Model model) | |||
| { | |||
| base.Update(model); | |||
| CategoryId = model.CategoryId; | |||
| if(model.Bitrate.IsSpecified) | |||
| Bitrate = model.Bitrate.Value; | |||
| @@ -59,41 +59,185 @@ namespace Discord.Rest | |||
| Update(model); | |||
| } | |||
| /// <summary> | |||
| /// Gets the parent (category) channel of 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. The task result contains the category channel | |||
| /// representing the parent of this channel; <c>null</c> if none is set. | |||
| /// </returns> | |||
| public Task<ICategoryChannel> GetCategoryAsync(RequestOptions options = null) | |||
| => ChannelHelper.GetCategoryAsync(this, Discord, options); | |||
| /// <inheritdoc /> | |||
| public Task SyncPermissionsAsync(RequestOptions options = null) | |||
| => ChannelHelper.SyncPermissionsAsync(this, Discord, options); | |||
| #endregion | |||
| /// <inheritdoc/> | |||
| /// <exception cref="InvalidOperationException">Cannot modify text channel properties of a voice channel.</exception> | |||
| public override Task ModifyAsync(Action<TextChannelProperties> func, RequestOptions options = null) | |||
| => throw new InvalidOperationException("Cannot modify text channel properties of a voice channel"); | |||
| #region Invites | |||
| /// <inheritdoc /> | |||
| public async Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); | |||
| /// <inheritdoc /> | |||
| public async Task<IInviteMetadata> CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); | |||
| /// <inheritdoc /> | |||
| public virtual async Task<IInviteMetadata> CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, (ulong)application, options); | |||
| /// <inheritdoc /> | |||
| public async Task<IInviteMetadata> CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); | |||
| /// <inheritdoc /> | |||
| public async Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | |||
| => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); | |||
| /// <inheritdoc/> | |||
| /// <exception cref="InvalidOperationException">Cannot create a thread within a voice channel.</exception> | |||
| public override Task<RestThreadChannel> CreateThreadAsync(string name, ThreadType type = ThreadType.PublicThread, ThreadArchiveDuration autoArchiveDuration = ThreadArchiveDuration.OneDay, IMessage message = null, bool? invitable = null, int? slowmode = null, RequestOptions options = null) | |||
| => throw new InvalidOperationException("Cannot create a thread within a voice channel"); | |||
| #endregion | |||
| private string DebuggerDisplay => $"{Name} ({Id}, Voice)"; | |||
| #region TextOverrides | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestMessage> GetMessageAsync(ulong id, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetMessageAsync(id, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task DeleteMessageAsync(IMessage message, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.DeleteMessageAsync(message, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.DeleteMessageAsync(messageId, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.DeleteMessagesAsync(messages, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.DeleteMessagesAsync(messageIds, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override IDisposable EnterTypingState(RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.EnterTypingState(options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = 100, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetMessagesAsync(fromMessage, dir, limit, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(int limit = 100, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetMessagesAsync(limit, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = 100, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetMessagesAsync(fromMessageId, dir, limit, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetPinnedMessagesAsync(options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestWebhook> GetWebhookAsync(ulong id, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetWebhookAsync(id, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<IReadOnlyCollection<RestWebhook>> GetWebhooksAsync(RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetWebhooksAsync(options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestWebhook> CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.CreateWebhookAsync(name, avatar, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<IUserMessage> ModifyMessageAsync(ulong messageId, Action<MessageProperties> func, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.ModifyMessageAsync(messageId, func, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestUserMessage> SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.SendFileAsync(attachment, text, isTTS, embed, options, allowedMentions, messageReference, components, stickers, embeds, flags); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, components, stickers, embeds, flags); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, components, stickers, embeds, flags); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestUserMessage> SendFilesAsync(IEnumerable<FileAttachment> attachments, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.SendFilesAsync(attachments, text, isTTS, embed, options, allowedMentions, messageReference, components, stickers, embeds, flags); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, components, stickers, embeds, flags); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task TriggerTypingAsync(RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.TriggerTypingAsync(options); | |||
| } | |||
| #endregion | |||
| #region IAudioChannel | |||
| /// <inheritdoc /> | |||
| /// <exception cref="NotSupportedException">Connecting to a REST-based channel is not supported.</exception> | |||
| @@ -1161,7 +1161,6 @@ namespace Discord.Rest | |||
| /// in order to use this property. | |||
| /// </remarks> | |||
| /// </param> | |||
| /// <param name="speakers">A collection of speakers for the event.</param> | |||
| /// <param name="location">The location of the event; links are supported</param> | |||
| /// <param name="coverImage">The optional banner image for the event.</param> | |||
| /// <param name="options">The options to be used when sending the request.</param> | |||
| @@ -65,8 +65,7 @@ namespace Discord.Rest | |||
| : ImmutableArray.Create<RestApplicationCommandOption>(); | |||
| IsEnabledInDm = model.DmPermission.GetValueOrDefault(true).GetValueOrDefault(true); | |||
| DefaultMemberPermissions = model.DefaultMemberPermission.GetValueOrDefault(null).HasValue | |||
| ? new GuildPermissions((ulong)model.DefaultMemberPermission.GetValueOrDefault(null).Value) : GuildPermissions.None; | |||
| DefaultMemberPermissions = new GuildPermissions((ulong)model.DefaultMemberPermission.GetValueOrDefault(0).GetValueOrDefault(0)); | |||
| } | |||
| /// <inheritdoc/> | |||
| @@ -333,7 +333,6 @@ namespace Discord.Rest | |||
| => await FollowupWithFilesAsync(attachments, text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options).ConfigureAwait(false); | |||
| /// <inheritdoc/> | |||
| Task IDiscordInteraction.RespondWithFilesAsync(IEnumerable<FileAttachment> attachments, string text, Embed[] embeds, bool isTTS, bool ephemeral, AllowedMentions allowedMentions, MessageComponent components, Embed embed, RequestOptions options) => throw new NotSupportedException("REST-Based interactions don't support files."); | |||
| /// <inheritdoc/> | |||
| #if NETCOREAPP3_0_OR_GREATER != true | |||
| /// <inheritdoc/> | |||
| Task IDiscordInteraction.RespondWithFileAsync(Stream fileStream, string fileName, string text, Embed[] embeds, bool isTTS, bool ephemeral, AllowedMentions allowedMentions, MessageComponent components, Embed embed, RequestOptions options) => throw new NotSupportedException("REST-Based interactions don't support files."); | |||
| @@ -144,7 +144,8 @@ namespace Discord.Rest | |||
| { | |||
| GuildId = model.Reference.Value.GuildId, | |||
| InternalChannelId = model.Reference.Value.ChannelId, | |||
| MessageId = model.Reference.Value.MessageId | |||
| MessageId = model.Reference.Value.MessageId, | |||
| FailIfNotExists = model.Reference.Value.FailIfNotExists | |||
| }; | |||
| } | |||
| @@ -25,7 +25,7 @@ namespace Discord.Rest | |||
| public string Name { get; private set; } | |||
| /// <inheritdoc /> | |||
| public string Icon { get; private set; } | |||
| /// <inheritdoc>/> | |||
| /// <inheritdoc /> | |||
| public Emoji Emoji { get; private set; } | |||
| /// <inheritdoc /> | |||
| public GuildPermissions Permissions { get; private set; } | |||
| @@ -87,6 +87,7 @@ namespace Discord.Rest | |||
| ChannelId = entity.InternalChannelId, | |||
| GuildId = entity.GuildId, | |||
| MessageId = entity.MessageId, | |||
| FailIfNotExists = entity.FailIfNotExists | |||
| }; | |||
| } | |||
| public static IEnumerable<string> EnumerateMentionTypes(this AllowedMentionTypes mentionTypes) | |||
| @@ -243,7 +243,7 @@ namespace Discord.Net.ED25519 | |||
| /// <summary> | |||
| /// // Decode a base58-encoded string into byte array | |||
| /// </summary> | |||
| /// <param name="strBase58">Base58 data string</param> | |||
| /// <param name="input">Base58 data string</param> | |||
| /// <returns>Byte array</returns> | |||
| public static byte[] Base58Decode(string input) | |||
| { | |||
| @@ -60,14 +60,9 @@ namespace Discord.Net.Queue | |||
| _clearToken?.Cancel(); | |||
| _clearToken?.Dispose(); | |||
| _clearToken = new CancellationTokenSource(); | |||
| if (_parentToken != null) | |||
| { | |||
| _requestCancelTokenSource?.Dispose(); | |||
| _requestCancelTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_clearToken.Token, _parentToken); | |||
| _requestCancelToken = _requestCancelTokenSource.Token; | |||
| } | |||
| else | |||
| _requestCancelToken = _clearToken.Token; | |||
| _requestCancelTokenSource?.Dispose(); | |||
| _requestCancelTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_clearToken.Token, _parentToken); | |||
| _requestCancelToken = _requestCancelTokenSource.Token; | |||
| } | |||
| finally { _tokenLock.Release(); } | |||
| } | |||
| @@ -8,6 +8,8 @@ | |||
| <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net6.0;net5.0;net461;netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">net6.0;net5.0;netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |||
| <WarningLevel>5</WarningLevel> | |||
| <TreatWarningsAsErrors>True</TreatWarningsAsErrors> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" /> | |||
| @@ -2331,7 +2331,9 @@ namespace Discord.WebSocket | |||
| SocketUser user = data.User.IsSpecified | |||
| ? State.GetOrAddUser(data.User.Value.Id, (_) => SocketGlobalUser.Create(this, State, data.User.Value)) | |||
| : guild?.AddOrUpdateUser(data.Member.Value); // null if the bot scope isn't set, so the guild cannot be retrieved. | |||
| : guild != null | |||
| ? guild.AddOrUpdateUser(data.Member.Value) // null if the bot scope isn't set, so the guild cannot be retrieved. | |||
| : State.GetOrAddUser(data.Member.Value.User.Id, (_) => SocketGlobalUser.Create(this, State, data.Member.Value.User)); | |||
| SocketChannel channel = null; | |||
| if(data.ChannelId.IsSpecified) | |||
| @@ -222,6 +222,8 @@ namespace Discord.WebSocket | |||
| #region IChannel | |||
| /// <inheritdoc /> | |||
| string IChannel.Name => Name; | |||
| /// <inheritdoc /> | |||
| IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | |||
| => ImmutableArray.Create<IReadOnlyCollection<IUser>>(Users).ToAsyncEnumerable(); //Overridden in Text/Voice | |||
| /// <inheritdoc /> | |||
| @@ -15,7 +15,11 @@ namespace Discord.WebSocket | |||
| public class SocketStageChannel : SocketVoiceChannel, IStageChannel | |||
| { | |||
| /// <inheritdoc/> | |||
| public string Topic { get; private set; } | |||
| /// <remarks> | |||
| /// This field is always false for stage channels. | |||
| /// </remarks> | |||
| public override bool IsTextInVoice | |||
| => false; | |||
| /// <inheritdoc/> | |||
| public StagePrivacyLevel? PrivacyLevel { get; private set; } | |||
| @@ -49,19 +53,16 @@ namespace Discord.WebSocket | |||
| entity.Update(state, model); | |||
| return entity; | |||
| } | |||
| internal void Update(StageInstance model, bool isLive = false) | |||
| { | |||
| IsLive = isLive; | |||
| if (isLive) | |||
| { | |||
| Topic = model.Topic; | |||
| PrivacyLevel = model.PrivacyLevel; | |||
| IsDiscoverableDisabled = model.DiscoverableDisabled; | |||
| } | |||
| else | |||
| { | |||
| Topic = null; | |||
| PrivacyLevel = null; | |||
| IsDiscoverableDisabled = null; | |||
| } | |||
| @@ -128,7 +128,7 @@ namespace Discord.WebSocket | |||
| #region Messages | |||
| /// <inheritdoc /> | |||
| public SocketMessage GetCachedMessage(ulong id) | |||
| public virtual SocketMessage GetCachedMessage(ulong id) | |||
| => _messages?.Get(id); | |||
| /// <summary> | |||
| /// Gets a message from this message channel. | |||
| @@ -143,7 +143,7 @@ namespace Discord.WebSocket | |||
| /// 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> | |||
| public async Task<IMessage> GetMessageAsync(ulong id, RequestOptions options = null) | |||
| public virtual async Task<IMessage> GetMessageAsync(ulong id, RequestOptions options = null) | |||
| { | |||
| IMessage msg = _messages?.Get(id); | |||
| if (msg == null) | |||
| @@ -163,7 +163,7 @@ namespace Discord.WebSocket | |||
| /// <returns> | |||
| /// Paged collection of messages. | |||
| /// </returns> | |||
| public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| public virtual IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => SocketChannelHelper.GetMessagesAsync(this, Discord, _messages, null, Direction.Before, limit, CacheMode.AllowDownload, options); | |||
| /// <summary> | |||
| /// Gets a collection of messages in this channel. | |||
| @@ -179,7 +179,7 @@ namespace Discord.WebSocket | |||
| /// <returns> | |||
| /// Paged collection of messages. | |||
| /// </returns> | |||
| public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| public virtual IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => SocketChannelHelper.GetMessagesAsync(this, Discord, _messages, fromMessageId, dir, limit, CacheMode.AllowDownload, options); | |||
| /// <summary> | |||
| /// Gets a collection of messages in this channel. | |||
| @@ -195,25 +195,25 @@ namespace Discord.WebSocket | |||
| /// <returns> | |||
| /// Paged collection of messages. | |||
| /// </returns> | |||
| public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| public virtual IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => SocketChannelHelper.GetMessagesAsync(this, Discord, _messages, fromMessage.Id, dir, limit, CacheMode.AllowDownload, options); | |||
| /// <inheritdoc /> | |||
| public IReadOnlyCollection<SocketMessage> GetCachedMessages(int limit = DiscordConfig.MaxMessagesPerBatch) | |||
| public virtual IReadOnlyCollection<SocketMessage> GetCachedMessages(int limit = DiscordConfig.MaxMessagesPerBatch) | |||
| => SocketChannelHelper.GetCachedMessages(this, Discord, _messages, null, Direction.Before, limit); | |||
| /// <inheritdoc /> | |||
| public IReadOnlyCollection<SocketMessage> GetCachedMessages(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) | |||
| public virtual IReadOnlyCollection<SocketMessage> GetCachedMessages(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) | |||
| => SocketChannelHelper.GetCachedMessages(this, Discord, _messages, fromMessageId, dir, limit); | |||
| /// <inheritdoc /> | |||
| public IReadOnlyCollection<SocketMessage> GetCachedMessages(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) | |||
| public virtual IReadOnlyCollection<SocketMessage> GetCachedMessages(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) | |||
| => SocketChannelHelper.GetCachedMessages(this, Discord, _messages, fromMessage.Id, dir, limit); | |||
| /// <inheritdoc /> | |||
| public Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(RequestOptions options = null) | |||
| public virtual Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(RequestOptions options = null) | |||
| => ChannelHelper.GetPinnedMessagesAsync(this, Discord, options); | |||
| /// <inheritdoc /> | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="ArgumentException">The only valid <see cref="MessageFlags"/> are <see cref="MessageFlags.SuppressEmbeds"/> and <see cref="MessageFlags.None"/>.</exception> | |||
| public Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, | |||
| public virtual Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, | |||
| RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, | |||
| MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, | |||
| @@ -221,7 +221,7 @@ namespace Discord.WebSocket | |||
| /// <inheritdoc /> | |||
| /// <exception cref="ArgumentException">The only valid <see cref="MessageFlags"/> are <see cref="MessageFlags.SuppressEmbeds"/> and <see cref="MessageFlags.None"/>.</exception> | |||
| public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, | |||
| public virtual Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, | |||
| RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, | |||
| MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, | |||
| Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| @@ -230,7 +230,7 @@ namespace Discord.WebSocket | |||
| /// <inheritdoc /> | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="ArgumentException">The only valid <see cref="MessageFlags"/> are <see cref="MessageFlags.SuppressEmbeds"/> and <see cref="MessageFlags.None"/>.</exception> | |||
| public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, | |||
| public virtual Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, | |||
| Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, | |||
| MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, | |||
| Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| @@ -239,7 +239,7 @@ namespace Discord.WebSocket | |||
| /// <inheritdoc /> | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="ArgumentException">The only valid <see cref="MessageFlags"/> are <see cref="MessageFlags.SuppressEmbeds"/> and <see cref="MessageFlags.None"/>.</exception> | |||
| public Task<RestUserMessage> SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, | |||
| public virtual Task<RestUserMessage> SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, | |||
| Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | |||
| MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, | |||
| Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| @@ -248,7 +248,7 @@ namespace Discord.WebSocket | |||
| /// <inheritdoc /> | |||
| /// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
| /// <exception cref="ArgumentException">The only valid <see cref="MessageFlags"/> are <see cref="MessageFlags.SuppressEmbeds"/> and <see cref="MessageFlags.None"/>.</exception> | |||
| public Task<RestUserMessage> SendFilesAsync(IEnumerable<FileAttachment> attachments, string text, bool isTTS = false, | |||
| public virtual Task<RestUserMessage> SendFilesAsync(IEnumerable<FileAttachment> attachments, string text, bool isTTS = false, | |||
| Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | |||
| MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, | |||
| Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| @@ -256,28 +256,28 @@ namespace Discord.WebSocket | |||
| messageReference, components, stickers, options, embeds, flags); | |||
| /// <inheritdoc /> | |||
| public Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null) | |||
| public virtual Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null) | |||
| => ChannelHelper.DeleteMessagesAsync(this, Discord, messages.Select(x => x.Id), options); | |||
| /// <inheritdoc /> | |||
| public Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null) | |||
| public virtual Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null) | |||
| => ChannelHelper.DeleteMessagesAsync(this, Discord, messageIds, options); | |||
| /// <inheritdoc /> | |||
| public async Task<IUserMessage> ModifyMessageAsync(ulong messageId, Action<MessageProperties> func, RequestOptions options = null) | |||
| public virtual async Task<IUserMessage> ModifyMessageAsync(ulong messageId, Action<MessageProperties> func, RequestOptions options = null) | |||
| => await ChannelHelper.ModifyMessageAsync(this, messageId, func, Discord, options).ConfigureAwait(false); | |||
| /// <inheritdoc /> | |||
| public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) | |||
| public virtual Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) | |||
| => ChannelHelper.DeleteMessageAsync(this, messageId, Discord, options); | |||
| /// <inheritdoc /> | |||
| public Task DeleteMessageAsync(IMessage message, RequestOptions options = null) | |||
| public virtual Task DeleteMessageAsync(IMessage message, RequestOptions options = null) | |||
| => ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options); | |||
| /// <inheritdoc /> | |||
| public Task TriggerTypingAsync(RequestOptions options = null) | |||
| public virtual Task TriggerTypingAsync(RequestOptions options = null) | |||
| => ChannelHelper.TriggerTypingAsync(this, Discord, options); | |||
| /// <inheritdoc /> | |||
| public IDisposable EnterTypingState(RequestOptions options = null) | |||
| public virtual IDisposable EnterTypingState(RequestOptions options = null) | |||
| => ChannelHelper.EnterTypingState(this, Discord, options); | |||
| internal void AddMessage(SocketMessage msg) | |||
| @@ -4,6 +4,7 @@ using System; | |||
| using System.Collections.Generic; | |||
| using System.Collections.Immutable; | |||
| using System.Diagnostics; | |||
| using System.IO; | |||
| using System.Linq; | |||
| using System.Threading.Tasks; | |||
| using Model = Discord.API.Channel; | |||
| @@ -14,33 +15,21 @@ namespace Discord.WebSocket | |||
| /// Represents a WebSocket-based voice channel in a guild. | |||
| /// </summary> | |||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
| public class SocketVoiceChannel : SocketGuildChannel, IVoiceChannel, ISocketAudioChannel | |||
| public class SocketVoiceChannel : SocketTextChannel, IVoiceChannel, ISocketAudioChannel | |||
| { | |||
| #region SocketVoiceChannel | |||
| /// <inheritdoc /> | |||
| public int Bitrate { get; private set; } | |||
| /// <inheritdoc /> | |||
| public int? UserLimit { get; private set; } | |||
| /// <inheritdoc/> | |||
| public string RTCRegion { get; private set; } | |||
| /// <inheritdoc /> | |||
| public ulong? CategoryId { get; private set; } | |||
| /// <summary> | |||
| /// Gets the parent (category) channel of this channel. | |||
| /// Gets whether or not the guild has Text-In-Voice enabled and the voice channel is a TiV channel. | |||
| /// </summary> | |||
| /// <returns> | |||
| /// A category channel representing the parent of this channel; <c>null</c> if none is set. | |||
| /// </returns> | |||
| public ICategoryChannel Category | |||
| => CategoryId.HasValue ? Guild.GetChannel(CategoryId.Value) as ICategoryChannel : null; | |||
| public virtual bool IsTextInVoice | |||
| => Guild.Features.HasTextInVoice; | |||
| /// <inheritdoc /> | |||
| public string Mention => MentionUtils.MentionChannel(Id); | |||
| public int Bitrate { get; private set; } | |||
| /// <inheritdoc /> | |||
| public int? UserLimit { get; private set; } | |||
| /// <inheritdoc /> | |||
| public Task SyncPermissionsAsync(RequestOptions options = null) | |||
| => ChannelHelper.SyncPermissionsAsync(this, Discord, options); | |||
| public string RTCRegion { get; private set; } | |||
| /// <summary> | |||
| /// Gets a collection of users that are currently connected to this voice channel. | |||
| @@ -48,7 +37,7 @@ namespace Discord.WebSocket | |||
| /// <returns> | |||
| /// A read-only collection of users that are currently connected to this voice channel. | |||
| /// </returns> | |||
| public override IReadOnlyCollection<SocketGuildUser> Users | |||
| public IReadOnlyCollection<SocketGuildUser> ConnectedUsers | |||
| => Guild.Users.Where(x => x.VoiceChannel?.Id == Id).ToImmutableArray(); | |||
| internal SocketVoiceChannel(DiscordSocketClient discord, ulong id, SocketGuild guild) | |||
| @@ -65,7 +54,6 @@ namespace Discord.WebSocket | |||
| internal override void Update(ClientState state, Model model) | |||
| { | |||
| base.Update(state, model); | |||
| CategoryId = model.CategoryId; | |||
| Bitrate = model.Bitrate.Value; | |||
| UserLimit = model.UserLimit.Value != 0 ? model.UserLimit.Value : (int?)null; | |||
| RTCRegion = model.RTCRegion.GetValueOrDefault(null); | |||
| @@ -99,28 +87,215 @@ namespace Discord.WebSocket | |||
| return user; | |||
| return null; | |||
| } | |||
| #endregion | |||
| #region Invites | |||
| /// <inheritdoc /> | |||
| public async Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); | |||
| /// <inheritdoc /> | |||
| public async Task<IInviteMetadata> CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); | |||
| /// <inheritdoc /> | |||
| public virtual async Task<IInviteMetadata> CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, (ulong)application, options); | |||
| /// <inheritdoc /> | |||
| public async Task<IInviteMetadata> CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); | |||
| /// <inheritdoc /> | |||
| public async Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | |||
| => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); | |||
| /// <inheritdoc/> <exception cref="InvalidOperationException">Cannot create threads in voice channels.</exception> | |||
| public override Task<SocketThreadChannel> CreateThreadAsync(string name, ThreadType type = ThreadType.PublicThread, ThreadArchiveDuration autoArchiveDuration = ThreadArchiveDuration.OneDay, IMessage message = null, bool? invitable = null, int? slowmode = null, RequestOptions options = null) | |||
| => throw new InvalidOperationException("Voice channels cannot contain threads."); | |||
| /// <inheritdoc/> <exception cref="InvalidOperationException">Cannot modify text channel properties for voice channels.</exception> | |||
| public override Task ModifyAsync(Action<TextChannelProperties> func, RequestOptions options = null) | |||
| => throw new InvalidOperationException("Cannot modify text channel properties for voice channels."); | |||
| #endregion | |||
| #region TextOverrides | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<IMessage> GetMessageAsync(ulong id, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetMessageAsync(id, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task DeleteMessageAsync(IMessage message, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.DeleteMessageAsync(message, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.DeleteMessageAsync(messageId, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.DeleteMessagesAsync(messages, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.DeleteMessagesAsync(messageIds, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override IDisposable EnterTypingState(RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.EnterTypingState(options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override SocketMessage GetCachedMessage(ulong id) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetCachedMessage(id); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override IReadOnlyCollection<SocketMessage> GetCachedMessages(IMessage fromMessage, Direction dir, int limit = 100) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetCachedMessages(fromMessage, dir, limit); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override IReadOnlyCollection<SocketMessage> GetCachedMessages(int limit = 100) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetCachedMessages(limit); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override IReadOnlyCollection<SocketMessage> GetCachedMessages(ulong fromMessageId, Direction dir, int limit = 100) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetCachedMessages(fromMessageId, dir, limit); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = 100, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetMessagesAsync(fromMessage, dir, limit, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = 100, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetMessagesAsync(limit, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = 100, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetMessagesAsync(fromMessageId, dir, limit, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetPinnedMessagesAsync(options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestWebhook> GetWebhookAsync(ulong id, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetWebhookAsync(id, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<IReadOnlyCollection<RestWebhook>> GetWebhooksAsync(RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.GetWebhooksAsync(options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestWebhook> CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.CreateWebhookAsync(name, avatar, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<IUserMessage> ModifyMessageAsync(ulong messageId, Action<MessageProperties> func, RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.ModifyMessageAsync(messageId, func, options); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestUserMessage> SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.SendFileAsync(attachment, text, isTTS, embed, options, allowedMentions, messageReference, components, stickers, embeds, flags); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, components, stickers, embeds, flags); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, components, stickers, embeds, flags); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestUserMessage> SendFilesAsync(IEnumerable<FileAttachment> attachments, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.SendFilesAsync(attachments, text, isTTS, embed, options, allowedMentions, messageReference, components, stickers, embeds, flags); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task<RestUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, components, stickers, embeds, flags); | |||
| } | |||
| /// <inheritdoc/> <exception cref="NotSupportedException">This function is only supported in Text-In-Voice channels.</exception> | |||
| public override Task TriggerTypingAsync(RequestOptions options = null) | |||
| { | |||
| if (!IsTextInVoice) | |||
| throw new NotSupportedException("This function is only supported in Text-In-Voice channels"); | |||
| return base.TriggerTypingAsync(options); | |||
| } | |||
| #endregion | |||
| private string DebuggerDisplay => $"{Name} ({Id}, Voice)"; | |||
| internal new SocketVoiceChannel Clone() => MemberwiseClone() as SocketVoiceChannel; | |||
| #endregion | |||
| #region IGuildChannel | |||
| /// <inheritdoc /> | |||
| @@ -1291,7 +1291,6 @@ namespace Discord.WebSocket | |||
| /// in order to use this property. | |||
| /// </remarks> | |||
| /// </param> | |||
| /// <param name="speakers">A collection of speakers for the event.</param> | |||
| /// <param name="location">The location of the event; links are supported</param> | |||
| /// <param name="coverImage">The optional banner image for the event.</param> | |||
| /// <param name="options">The options to be used when sending the request.</param> | |||
| @@ -174,6 +174,91 @@ namespace Discord.WebSocket | |||
| HasResponded = true; | |||
| } | |||
| public async Task UpdateAsync(Action<MessageProperties> func, RequestOptions options = null) | |||
| { | |||
| var args = new MessageProperties(); | |||
| func(args); | |||
| if (!IsValidToken) | |||
| throw new InvalidOperationException("Interaction token is no longer valid"); | |||
| if (!InteractionHelper.CanSendResponse(this)) | |||
| throw new TimeoutException($"Cannot respond to an interaction after {InteractionHelper.ResponseTimeLimit} seconds!"); | |||
| if (args.AllowedMentions.IsSpecified) | |||
| { | |||
| var allowedMentions = args.AllowedMentions.Value; | |||
| Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions), "A max of 100 role Ids are allowed."); | |||
| Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions), "A max of 100 user Ids are allowed."); | |||
| } | |||
| var embed = args.Embed; | |||
| var embeds = args.Embeds; | |||
| bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : false; | |||
| bool hasEmbeds = embed.IsSpecified && embed.Value != null || embeds.IsSpecified && embeds.Value?.Length > 0; | |||
| if (!hasText && !hasEmbeds) | |||
| Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); | |||
| var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List<API.Embed>() : null; | |||
| if (embed.IsSpecified && embed.Value != null) | |||
| { | |||
| apiEmbeds.Add(embed.Value.ToModel()); | |||
| } | |||
| if (embeds.IsSpecified && embeds.Value != null) | |||
| { | |||
| apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); | |||
| } | |||
| Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); | |||
| // check that user flag and user Id list are exclusive, same with role flag and role Id list | |||
| if (args.AllowedMentions.IsSpecified && args.AllowedMentions.Value != null && args.AllowedMentions.Value.AllowedTypes.HasValue) | |||
| { | |||
| var allowedMentions = args.AllowedMentions.Value; | |||
| if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Users) | |||
| && allowedMentions.UserIds != null && allowedMentions.UserIds.Count > 0) | |||
| { | |||
| throw new ArgumentException("The Users flag is mutually exclusive with the list of User Ids.", nameof(args.AllowedMentions)); | |||
| } | |||
| if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Roles) | |||
| && allowedMentions.RoleIds != null && allowedMentions.RoleIds.Count > 0) | |||
| { | |||
| throw new ArgumentException("The Roles flag is mutually exclusive with the list of Role Ids.", nameof(args.AllowedMentions)); | |||
| } | |||
| } | |||
| var response = new API.InteractionResponse | |||
| { | |||
| Type = InteractionResponseType.UpdateMessage, | |||
| Data = new API.InteractionCallbackData | |||
| { | |||
| Content = args.Content, | |||
| AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value?.ToModel() : Optional<API.AllowedMentions>.Unspecified, | |||
| Embeds = apiEmbeds?.ToArray() ?? Optional<API.Embed[]>.Unspecified, | |||
| Components = args.Components.IsSpecified | |||
| ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Array.Empty<API.ActionRowComponent>() | |||
| : Optional<API.ActionRowComponent[]>.Unspecified, | |||
| Flags = args.Flags.IsSpecified ? args.Flags.Value ?? Optional<MessageFlags>.Unspecified : Optional<MessageFlags>.Unspecified | |||
| } | |||
| }; | |||
| lock (_lock) | |||
| { | |||
| if (HasResponded) | |||
| { | |||
| throw new InvalidOperationException("Cannot respond, update, or defer twice to the same interaction"); | |||
| } | |||
| } | |||
| await InteractionHelper.SendInteractionResponseAsync(Discord, response, this, Channel, options).ConfigureAwait(false); | |||
| HasResponded = true; | |||
| } | |||
| /// <inheritdoc/> | |||
| public override async Task<RestFollowupMessage> FollowupAsync( | |||
| string text = null, | |||
| @@ -94,8 +94,7 @@ namespace Discord.WebSocket | |||
| : ImmutableArray.Create<SocketApplicationCommandOption>(); | |||
| IsEnabledInDm = model.DmPermission.GetValueOrDefault(true).GetValueOrDefault(true); | |||
| DefaultMemberPermissions = model.DefaultMemberPermission.GetValueOrDefault(null).HasValue | |||
| ? new GuildPermissions((ulong)model.DefaultMemberPermission.GetValueOrDefault(null).Value) : GuildPermissions.None; | |||
| DefaultMemberPermissions = new GuildPermissions((ulong)model.DefaultMemberPermission.GetValueOrDefault(0).GetValueOrDefault(0)); | |||
| } | |||
| /// <inheritdoc/> | |||
| @@ -182,7 +182,8 @@ namespace Discord.WebSocket | |||
| { | |||
| GuildId = model.Reference.Value.GuildId, | |||
| InternalChannelId = model.Reference.Value.ChannelId, | |||
| MessageId = model.Reference.Value.MessageId | |||
| MessageId = model.Reference.Value.MessageId, | |||
| FailIfNotExists = model.Reference.Value.FailIfNotExists | |||
| }; | |||
| } | |||
| @@ -6,6 +6,8 @@ | |||
| <RootNamespace>Discord.Webhook</RootNamespace> | |||
| <Description>A core Discord.Net library containing the Webhook client and models.</Description> | |||
| <TargetFrameworks>net6.0;net5.0;netstandard2.0;netstandard2.1</TargetFrameworks> | |||
| <WarningLevel>5</WarningLevel> | |||
| <TreatWarningsAsErrors>True</TreatWarningsAsErrors> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" /> | |||
| @@ -88,8 +88,8 @@ namespace Discord.Webhook | |||
| /// <returns> Returns the ID of the created message. </returns> | |||
| public Task<ulong> SendMessageAsync(string text = null, bool isTTS = false, IEnumerable<Embed> embeds = null, | |||
| string username = null, string avatarUrl = null, RequestOptions options = null, AllowedMentions allowedMentions = null, | |||
| MessageComponent components = null, MessageFlags flags = MessageFlags.None) | |||
| => WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, components, flags); | |||
| MessageComponent components = null, MessageFlags flags = MessageFlags.None, ulong? threadId = null) | |||
| => WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, components, flags, threadId); | |||
| /// <summary> | |||
| /// Modifies a message posted using this webhook. | |||
| @@ -103,8 +103,8 @@ namespace Discord.Webhook | |||
| /// <returns> | |||
| /// A task that represents the asynchronous modification operation. | |||
| /// </returns> | |||
| public Task ModifyMessageAsync(ulong messageId, Action<WebhookMessageProperties> func, RequestOptions options = null) | |||
| => WebhookClientHelper.ModifyMessageAsync(this, messageId, func, options); | |||
| public Task ModifyMessageAsync(ulong messageId, Action<WebhookMessageProperties> func, RequestOptions options = null, ulong? threadId = null) | |||
| => WebhookClientHelper.ModifyMessageAsync(this, messageId, func, options, threadId); | |||
| /// <summary> | |||
| /// Deletes a message posted using this webhook. | |||
| @@ -117,43 +117,43 @@ namespace Discord.Webhook | |||
| /// <returns> | |||
| /// A task that represents the asynchronous deletion operation. | |||
| /// </returns> | |||
| public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) | |||
| => WebhookClientHelper.DeleteMessageAsync(this, messageId, options); | |||
| public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null, ulong ? threadId = null) | |||
| => WebhookClientHelper.DeleteMessageAsync(this, messageId, options, threadId); | |||
| /// <summary> Sends a message to the channel for this webhook with an attachment. </summary> | |||
| /// <returns> Returns the ID of the created message. </returns> | |||
| public Task<ulong> SendFileAsync(string filePath, string text, bool isTTS = false, | |||
| IEnumerable<Embed> embeds = null, string username = null, string avatarUrl = null, | |||
| RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, | |||
| MessageComponent components = null, MessageFlags flags = MessageFlags.None) | |||
| MessageComponent components = null, MessageFlags flags = MessageFlags.None, ulong? threadId = null) | |||
| => WebhookClientHelper.SendFileAsync(this, filePath, text, isTTS, embeds, username, avatarUrl, | |||
| allowedMentions, options, isSpoiler, components, flags); | |||
| allowedMentions, options, isSpoiler, components, flags, threadId); | |||
| /// <summary> Sends a message to the channel for this webhook with an attachment. </summary> | |||
| /// <returns> Returns the ID of the created message. </returns> | |||
| public Task<ulong> SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, | |||
| IEnumerable<Embed> embeds = null, string username = null, string avatarUrl = null, | |||
| RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, | |||
| MessageComponent components = null, MessageFlags flags = MessageFlags.None) | |||
| MessageComponent components = null, MessageFlags flags = MessageFlags.None, ulong? threadId = null) | |||
| => WebhookClientHelper.SendFileAsync(this, stream, filename, text, isTTS, embeds, username, | |||
| avatarUrl, allowedMentions, options, isSpoiler, components, flags); | |||
| avatarUrl, allowedMentions, options, isSpoiler, components, flags, threadId); | |||
| /// <summary> Sends a message to the channel for this webhook with an attachment. </summary> | |||
| /// <returns> Returns the ID of the created message. </returns> | |||
| public Task<ulong> SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, | |||
| IEnumerable<Embed> embeds = null, string username = null, string avatarUrl = null, | |||
| RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent components = null, | |||
| MessageFlags flags = MessageFlags.None) | |||
| MessageFlags flags = MessageFlags.None, ulong? threadId = null) | |||
| => WebhookClientHelper.SendFileAsync(this, attachment, text, isTTS, embeds, username, | |||
| avatarUrl, allowedMentions, components, options, flags); | |||
| avatarUrl, allowedMentions, components, options, flags, threadId); | |||
| /// <summary> Sends a message to the channel for this webhook with an attachment. </summary> | |||
| /// <returns> Returns the ID of the created message. </returns> | |||
| public Task<ulong> SendFilesAsync(IEnumerable<FileAttachment> attachments, string text, bool isTTS = false, | |||
| IEnumerable<Embed> embeds = null, string username = null, string avatarUrl = null, | |||
| RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent components = null, | |||
| MessageFlags flags = MessageFlags.None) | |||
| MessageFlags flags = MessageFlags.None, ulong? threadId = null) | |||
| => WebhookClientHelper.SendFilesAsync(this, attachments, text, isTTS, embeds, username, avatarUrl, | |||
| allowedMentions, components, options, flags); | |||
| allowedMentions, components, options, flags, threadId); | |||
| /// <summary> Modifies the properties of this webhook. </summary> | |||
| @@ -21,8 +21,8 @@ namespace Discord.Webhook | |||
| return RestInternalWebhook.Create(client, model); | |||
| } | |||
| public static async Task<ulong> SendMessageAsync(DiscordWebhookClient client, | |||
| string text, bool isTTS, IEnumerable<Embed> embeds, string username, string avatarUrl, | |||
| AllowedMentions allowedMentions, RequestOptions options, MessageComponent components, MessageFlags flags) | |||
| string text, bool isTTS, IEnumerable<Embed> embeds, string username, string avatarUrl, | |||
| AllowedMentions allowedMentions, RequestOptions options, MessageComponent components, MessageFlags flags, ulong? threadId = null) | |||
| { | |||
| var args = new CreateWebhookMessageParams | |||
| { | |||
| @@ -44,12 +44,13 @@ namespace Discord.Webhook | |||
| if (flags is not MessageFlags.None and not MessageFlags.SuppressEmbeds) | |||
| throw new ArgumentException("The only valid MessageFlags are SuppressEmbeds and none.", nameof(flags)); | |||
| var model = await client.ApiClient.CreateWebhookMessageAsync(client.Webhook.Id, args, options: options).ConfigureAwait(false); | |||
| var model = await client.ApiClient.CreateWebhookMessageAsync(client.Webhook.Id, args, options: options, threadId: threadId).ConfigureAwait(false); | |||
| return model.Id; | |||
| } | |||
| public static async Task ModifyMessageAsync(DiscordWebhookClient client, ulong messageId, | |||
| Action<WebhookMessageProperties> func, RequestOptions options) | |||
| Action<WebhookMessageProperties> func, RequestOptions options, ulong? threadId) | |||
| { | |||
| var args = new WebhookMessageProperties(); | |||
| func(args); | |||
| @@ -94,35 +95,35 @@ namespace Discord.Webhook | |||
| Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional<API.ActionRowComponent[]>.Unspecified, | |||
| }; | |||
| await client.ApiClient.ModifyWebhookMessageAsync(client.Webhook.Id, messageId, apiArgs, options) | |||
| await client.ApiClient.ModifyWebhookMessageAsync(client.Webhook.Id, messageId, apiArgs, options, threadId) | |||
| .ConfigureAwait(false); | |||
| } | |||
| public static async Task DeleteMessageAsync(DiscordWebhookClient client, ulong messageId, RequestOptions options) | |||
| public static async Task DeleteMessageAsync(DiscordWebhookClient client, ulong messageId, RequestOptions options, ulong? threadId) | |||
| { | |||
| await client.ApiClient.DeleteWebhookMessageAsync(client.Webhook.Id, messageId, options).ConfigureAwait(false); | |||
| await client.ApiClient.DeleteWebhookMessageAsync(client.Webhook.Id, messageId, options, threadId).ConfigureAwait(false); | |||
| } | |||
| public static async Task<ulong> SendFileAsync(DiscordWebhookClient client, string filePath, string text, bool isTTS, | |||
| IEnumerable<Embed> embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options, | |||
| bool isSpoiler, MessageComponent components, MessageFlags flags = MessageFlags.None) | |||
| bool isSpoiler, MessageComponent components, MessageFlags flags = MessageFlags.None, ulong? threadId = null) | |||
| { | |||
| string filename = Path.GetFileName(filePath); | |||
| using (var file = File.OpenRead(filePath)) | |||
| return await SendFileAsync(client, file, filename, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, isSpoiler, components, flags).ConfigureAwait(false); | |||
| return await SendFileAsync(client, file, filename, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, isSpoiler, components, flags, threadId).ConfigureAwait(false); | |||
| } | |||
| public static Task<ulong> SendFileAsync(DiscordWebhookClient client, Stream stream, string filename, string text, bool isTTS, | |||
| IEnumerable<Embed> embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options, bool isSpoiler, | |||
| MessageComponent components, MessageFlags flags) | |||
| => SendFileAsync(client, new FileAttachment(stream, filename, isSpoiler: isSpoiler), text, isTTS, embeds, username, avatarUrl, allowedMentions, components, options, flags); | |||
| MessageComponent components, MessageFlags flags, ulong? threadId) | |||
| => SendFileAsync(client, new FileAttachment(stream, filename, isSpoiler: isSpoiler), text, isTTS, embeds, username, avatarUrl, allowedMentions, components, options, flags, threadId); | |||
| public static Task<ulong> SendFileAsync(DiscordWebhookClient client, FileAttachment attachment, string text, bool isTTS, | |||
| IEnumerable<Embed> embeds, string username, string avatarUrl, AllowedMentions allowedMentions, | |||
| MessageComponent components, RequestOptions options, MessageFlags flags) | |||
| => SendFilesAsync(client, new FileAttachment[] { attachment }, text, isTTS, embeds, username, avatarUrl, allowedMentions, components, options, flags); | |||
| MessageComponent components, RequestOptions options, MessageFlags flags, ulong? threadId) | |||
| => SendFilesAsync(client, new FileAttachment[] { attachment }, text, isTTS, embeds, username, avatarUrl, allowedMentions, components, options, flags, threadId); | |||
| public static async Task<ulong> SendFilesAsync(DiscordWebhookClient client, | |||
| IEnumerable<FileAttachment> attachments, string text, bool isTTS, IEnumerable<Embed> embeds, string username, | |||
| string avatarUrl, AllowedMentions allowedMentions, MessageComponent components, RequestOptions options, | |||
| MessageFlags flags) | |||
| MessageFlags flags, ulong? threadId) | |||
| { | |||
| embeds ??= Array.Empty<Embed>(); | |||
| @@ -164,7 +165,7 @@ namespace Discord.Webhook | |||
| MessageComponents = components?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified, | |||
| Flags = flags | |||
| }; | |||
| var msg = await client.ApiClient.UploadWebhookFileAsync(client.Webhook.Id, args, options).ConfigureAwait(false); | |||
| var msg = await client.ApiClient.UploadWebhookFileAsync(client.Webhook.Id, args, options, threadId).ConfigureAwait(false); | |||
| return msg.Id; | |||
| } | |||
| @@ -2,57 +2,57 @@ | |||
| <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> | |||
| <metadata> | |||
| <id>Discord.Net</id> | |||
| <version>3.6.0$suffix$</version> | |||
| <version>3.6.1$suffix$</version> | |||
| <title>Discord.Net</title> | |||
| <authors>Discord.Net Contributors</authors> | |||
| <owners>foxbot</owners> | |||
| <description>An asynchronous API wrapper for Discord. This metapackage includes all of the optional Discord.Net components.</description> | |||
| <tags>discord;discordapp</tags> | |||
| <projectUrl>https://github.com/RogueException/Discord.Net</projectUrl> | |||
| <projectUrl>https://github.com/discord-net/Discord.Net</projectUrl> | |||
| <licenseUrl>http://opensource.org/licenses/MIT</licenseUrl> | |||
| <requireLicenseAcceptance>false</requireLicenseAcceptance> | |||
| <iconUrl>https://github.com/RogueException/Discord.Net/raw/dev/docs/marketing/logo/PackageLogo.png</iconUrl> | |||
| <iconUrl>https://github.com/discord-net/Discord.Net/raw/dev/docs/marketing/logo/PackageLogo.png</iconUrl> | |||
| <dependencies> | |||
| <group targetFramework="net6.0"> | |||
| <dependency id="Discord.Net.Core" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Rest" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.WebSocket" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Commands" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Webhook" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Interactions" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Core" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Rest" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.WebSocket" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Commands" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Webhook" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Interactions" version="3.6.1$suffix$" /> | |||
| </group> | |||
| <group targetFramework="net5.0"> | |||
| <dependency id="Discord.Net.Core" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Rest" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.WebSocket" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Commands" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Webhook" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Interactions" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Core" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Rest" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.WebSocket" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Commands" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Webhook" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Interactions" version="3.6.1$suffix$" /> | |||
| </group> | |||
| <group targetFramework="net461"> | |||
| <dependency id="Discord.Net.Core" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Rest" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.WebSocket" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Commands" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Webhook" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Interactions" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Core" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Rest" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.WebSocket" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Commands" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Webhook" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Interactions" version="3.6.1$suffix$" /> | |||
| </group> | |||
| <group targetFramework="netstandard2.0"> | |||
| <dependency id="Discord.Net.Core" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Rest" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.WebSocket" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Commands" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Webhook" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Interactions" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Core" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Rest" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.WebSocket" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Commands" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Webhook" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Interactions" version="3.6.1$suffix$" /> | |||
| </group> | |||
| <group targetFramework="netstandard2.1"> | |||
| <dependency id="Discord.Net.Core" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Rest" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.WebSocket" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Commands" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Webhook" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Interactions" version="3.6.0$suffix$" /> | |||
| <dependency id="Discord.Net.Core" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Rest" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.WebSocket" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Commands" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Webhook" version="3.6.1$suffix$" /> | |||
| <dependency id="Discord.Net.Interactions" version="3.6.1$suffix$" /> | |||
| </group> | |||
| </dependencies> | |||
| </metadata> | |||
| </package> | |||
| </package> | |||
| @@ -1,5 +1,6 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.IO; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| using Discord.Audio; | |||
| @@ -12,8 +13,6 @@ namespace Discord | |||
| public int? UserLimit => throw new NotImplementedException(); | |||
| public string Mention => throw new NotImplementedException(); | |||
| public ulong? CategoryId => throw new NotImplementedException(); | |||
| public int Position => throw new NotImplementedException(); | |||
| @@ -24,116 +23,53 @@ namespace Discord | |||
| public IReadOnlyCollection<Overwrite> PermissionOverwrites => throw new NotImplementedException(); | |||
| public string RTCRegion => throw new NotImplementedException(); | |||
| public string Name => throw new NotImplementedException(); | |||
| public DateTimeOffset CreatedAt => throw new NotImplementedException(); | |||
| public ulong Id => throw new NotImplementedException(); | |||
| public string RTCRegion => throw new NotImplementedException(); | |||
| public Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions, RequestOptions options = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public ulong Id => throw new NotImplementedException(); | |||
| public Task<IAudioClient> ConnectAsync(bool selfDeaf = false, bool selfMute = false, bool external = false) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public string Mention => throw new NotImplementedException(); | |||
| public Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public Task<IInviteMetadata> CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => throw new NotImplementedException(); | |||
| public Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task<IAudioClient> ConnectAsync(bool selfDeaf = false, bool selfMute = false, bool external = false) => throw new NotImplementedException(); | |||
| public Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task<IInviteMetadata> CreateInviteToApplicationAsync(ulong applicationId, int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task<IInviteMetadata> CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task<IInviteMetadata> CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||
| => throw new NotImplementedException(); | |||
| public Task DeleteAsync(RequestOptions options = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public Task DisconnectAsync() | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public Task ModifyAsync(Action<AudioChannelProperties> func, RequestOptions options) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public Task<ICategoryChannel> GetCategoryAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public OverwritePermissions? GetPermissionOverwrite(IRole role) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public OverwritePermissions? GetPermissionOverwrite(IUser user) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public Task<IGuildUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public Task ModifyAsync(Action<VoiceChannelProperties> func, RequestOptions options = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public Task ModifyAsync(Action<GuildChannelProperties> func, RequestOptions options = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public Task RemovePermissionOverwriteAsync(IRole role, RequestOptions options = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public Task RemovePermissionOverwriteAsync(IUser user, RequestOptions options = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public Task SyncPermissionsAsync(RequestOptions options = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public Task<IInviteMetadata> CreateInviteToStreamAsync(IUser user, int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task DeleteAsync(RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task DeleteMessageAsync(IMessage message, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task DisconnectAsync() => throw new NotImplementedException(); | |||
| public IDisposable EnterTypingState(RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task<ICategoryChannel> GetCategoryAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task<IMessage> GetMessageAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = 100, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = 100, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = 100, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public OverwritePermissions? GetPermissionOverwrite(IRole role) => throw new NotImplementedException(); | |||
| public OverwritePermissions? GetPermissionOverwrite(IUser user) => throw new NotImplementedException(); | |||
| public Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync(RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task<IGuildUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task ModifyAsync(Action<VoiceChannelProperties> func, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task ModifyAsync(Action<GuildChannelProperties> func, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task ModifyAsync(Action<AudioChannelProperties> func, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task<IUserMessage> ModifyMessageAsync(ulong messageId, Action<MessageProperties> func, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task RemovePermissionOverwriteAsync(IRole role, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task RemovePermissionOverwriteAsync(IUser user, RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) => throw new NotImplementedException(); | |||
| public Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) => throw new NotImplementedException(); | |||
| public Task<IUserMessage> SendFileAsync(FileAttachment attachment, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) => throw new NotImplementedException(); | |||
| public Task<IUserMessage> SendFilesAsync(IEnumerable<FileAttachment> attachments, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) => throw new NotImplementedException(); | |||
| public Task<IUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null, MessageFlags flags = MessageFlags.None) => throw new NotImplementedException(); | |||
| public Task SyncPermissionsAsync(RequestOptions options = null) => throw new NotImplementedException(); | |||
| public Task TriggerTypingAsync(RequestOptions options = null) => throw new NotImplementedException(); | |||
| Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => throw new NotImplementedException(); | |||
| IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => throw new NotImplementedException(); | |||
| } | |||
| } | |||