diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml index 8e54d8ab6..72820de90 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.xml +++ b/src/Discord.Net.Core/Discord.Net.Core.xml @@ -3410,6 +3410,28 @@ admins and moderators of Community guilds receive notices from Discord; if none is set. + + + Gets a thread channel within this guild. + + The id of the thread channel. + The that determines whether the object should be fetched from cache. + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains the thread channel. + + + + + Gets a collection of all thread channels in this guild. + + The that determines whether the object should be fetched from cache. + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains a read-only collection of + thread channels found within this guild. + + Creates a new text channel in this guild. diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs index e3b0533eb..e0be51cf5 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs @@ -589,6 +589,26 @@ namespace Discord /// admins and moderators of Community guilds receive notices from Discord; if none is set. /// Task GetPublicUpdatesChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); + /// + /// Gets a thread channel within this guild. + /// + /// The id of the thread channel. + /// The that determines whether the object should be fetched from cache. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains the thread channel. + /// + Task GetThreadChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); + /// + /// Gets a collection of all thread channels in this guild. + /// + /// The that determines whether the object should be fetched from cache. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection of + /// thread channels found within this guild. + /// + Task> GetThreadChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// /// Creates a new text channel in this guild. diff --git a/src/Discord.Net.Rest/Discord.Net.Rest.xml b/src/Discord.Net.Rest/Discord.Net.Rest.xml index a30a6e2b4..3aaa2c6a2 100644 --- a/src/Discord.Net.Rest/Discord.Net.Rest.xml +++ b/src/Discord.Net.Rest/Discord.Net.Rest.xml @@ -3088,6 +3088,27 @@ message channels found within this guild. + + + Gets a thread channel in this guild. + + The snowflake identifier for the thread channel. + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains the thread channel associated + with the specified ; if none is found. + + + + + Gets a collection of all thread in this guild. + + The options to be used when sending the request. + + A task that represents the asynchronous get operation. The task result contains a read-only collection of + threads found within this guild. + + Gets a voice channel in this guild. @@ -3463,6 +3484,12 @@ + + + + + + diff --git a/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs index fdfee39ea..27d6cd1a6 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs @@ -42,6 +42,8 @@ namespace Discord.Rest return RestVoiceChannel.Create(discord, guild, model); case ChannelType.Category: return RestCategoryChannel.Create(discord, guild, model); + case ChannelType.PublicThread or ChannelType.PrivateThread or ChannelType.NewsThread: + return RestThreadChannel.Create(discord, guild, model); default: return new RestGuildChannel(discord, guild, model.Id); } diff --git a/src/Discord.Net.Rest/Entities/Channels/ThreadHelper.cs b/src/Discord.Net.Rest/Entities/Channels/ThreadHelper.cs index 958210d85..f1bf238bc 100644 --- a/src/Discord.Net.Rest/Entities/Channels/ThreadHelper.cs +++ b/src/Discord.Net.Rest/Entities/Channels/ThreadHelper.cs @@ -19,6 +19,9 @@ namespace Discord.Rest if (autoArchiveDuration == ThreadArchiveDuration.ThreeDays && !channel.Guild.Features.Contains("THREE_DAY_THREAD_ARCHIVE")) throw new ArgumentException($"The guild {channel.Guild.Name} does not have the THREE_DAY_THREAD_ARCHIVE feature!"); + if (type == ThreadType.PrivateThread && !channel.Guild.Features.Contains("PRIVATE_THREADS")) + throw new ArgumentException($"The guild {channel.Guild.Name} does not have the PRIVATE_THREADS feature!"); + var args = new StartThreadParams() { Name = name, diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs index a130dcef9..a184f1290 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs @@ -394,6 +394,35 @@ namespace Discord.Rest return channels.OfType().ToImmutableArray(); } + /// + /// Gets a thread channel in this guild. + /// + /// The snowflake identifier for the thread channel. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains the thread channel associated + /// with the specified ; if none is found. + /// + public async Task GetThreadChannelAsync(ulong id, RequestOptions options = null) + { + var channel = await GuildHelper.GetChannelAsync(this, Discord, id, options).ConfigureAwait(false); + return channel as RestThreadChannel; + } + + /// + /// Gets a collection of all thread in this guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection of + /// threads found within this guild. + /// + public async Task> GetThreadChannelsAsync(RequestOptions options = null) + { + var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); + return channels.OfType().ToImmutableArray(); + } + /// /// Gets a voice channel in this guild. /// @@ -891,6 +920,22 @@ namespace Discord.Rest return null; } /// + async Task IGuild.GetThreadChannelAsync(ulong id, CacheMode mode, RequestOptions options) + { + if (mode == CacheMode.AllowDownload) + return await GetThreadChannelAsync(id, options).ConfigureAwait(false); + else + return null; + } + /// + async Task> IGuild.GetThreadChannelsAsync(CacheMode mode, RequestOptions options) + { + if (mode == CacheMode.AllowDownload) + return await GetThreadChannelsAsync(options).ConfigureAwait(false); + else + return null; + } + /// async Task> IGuild.GetVoiceChannelsAsync(CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) diff --git a/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs index d49afff25..32f79f3d1 100644 --- a/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs +++ b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs @@ -542,7 +542,7 @@ namespace Discord.WebSocket internal readonly AsyncEvent> _applicationCommandDeleted = new AsyncEvent>(); /// - /// Fired when a thread is created within a guild. + /// Fired when a thread is created within a guild, or when the current user is added to a thread. /// public event Func ThreadCreated { diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml index 90cc3dbd2..01d919d2b 100644 --- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml +++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml @@ -758,7 +758,7 @@ - Fired when a thread is created within a guild. + Fired when a thread is created within a guild. or when the current user is added to a thread. @@ -3058,6 +3058,15 @@ A text channel associated with the specified ; if none is found. + + + Gets a thread in this guild. + + The snowflake identifier for the thread. + + A thread channel associated with the specified ; if none is found. + + Gets a voice channel in this guild. @@ -3393,6 +3402,12 @@ + + + + + + diff --git a/src/Discord.Net.WebSocket/DiscordShardedClient.cs b/src/Discord.Net.WebSocket/DiscordShardedClient.cs index 386f9f7e5..18272eef2 100644 --- a/src/Discord.Net.WebSocket/DiscordShardedClient.cs +++ b/src/Discord.Net.WebSocket/DiscordShardedClient.cs @@ -379,6 +379,13 @@ namespace Discord.WebSocket client.InviteDeleted += (channel, invite) => _inviteDeletedEvent.InvokeAsync(channel, invite); client.InteractionCreated += (interaction) => _interactionCreatedEvent.InvokeAsync(interaction); + + client.ThreadUpdated += (thread1, thread2) => _threadUpdated.InvokeAsync(thread1, thread2); + client.ThreadCreated += (thread) => _threadCreated.InvokeAsync(thread); + client.ThreadDeleted += (thread) => _threadDeleted.InvokeAsync(thread); + + client.ThreadMemberJoined += (user) => _threadMemberJoined.InvokeAsync(user); + client.ThreadMemberLeft += (user) => _threadMemberLeft.InvokeAsync(user); } //IDiscordClient diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index 12802247d..14a9bbbe8 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -2001,8 +2001,9 @@ namespace Discord.WebSocket threadChannel = (SocketThreadChannel)guild.AddChannel(this.State, data); if (data.ThreadMember.IsSpecified) threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser); - await TimedInvokeAsync(_threadCreated, nameof(ThreadCreated), threadChannel).ConfigureAwait(false); } + + await TimedInvokeAsync(_threadCreated, nameof(ThreadCreated), threadChannel).ConfigureAwait(false); } break; diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketThreadChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketThreadChannel.cs index 8065a8b2b..33832096b 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketThreadChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketThreadChannel.cs @@ -281,14 +281,14 @@ namespace Discord.WebSocket /// This method is not supported in threads. /// public override OverwritePermissions? GetPermissionOverwrite(IRole role) - => throw new NotImplementedException(); + => ParentChannel.GetPermissionOverwrite(role); /// /// /// This method is not supported in threads. /// public override OverwritePermissions? GetPermissionOverwrite(IUser user) - => throw new NotImplementedException(); + => ParentChannel.GetPermissionOverwrite(user); /// /// diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index 2fef6ff09..33c266beb 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -633,6 +633,16 @@ namespace Discord.WebSocket public SocketTextChannel GetTextChannel(ulong id) => GetChannel(id) as SocketTextChannel; /// + /// Gets a thread in this guild. + /// + /// The snowflake identifier for the thread. + /// + /// A thread channel associated with the specified ; if none is found. + /// + public SocketThreadChannel GetThreadChannel(ulong id) + => GetChannel(id) as SocketThreadChannel; + + /// /// Gets a voice channel in this guild. /// /// The snowflake identifier for the voice channel. @@ -1329,6 +1339,12 @@ namespace Discord.WebSocket Task IGuild.GetTextChannelAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(GetTextChannel(id)); /// + Task IGuild.GetThreadChannelAsync(ulong id, CacheMode mode, RequestOptions options) + => Task.FromResult(GetThreadChannel(id)); + /// + Task> IGuild.GetThreadChannelsAsync(CacheMode mode, RequestOptions options) + => Task.FromResult>(ThreadChannels); + /// Task> IGuild.GetVoiceChannelsAsync(CacheMode mode, RequestOptions options) => Task.FromResult>(VoiceChannels); ///