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);
///