From 1b7b98d34f8098bbd820df836361cb6f1691736d Mon Sep 17 00:00:00 2001 From: AraHaan Date: Tue, 26 May 2026 03:32:36 -0400 Subject: [PATCH 1/3] Bug fix to allow the calls to webhook APIs to succeed when using GuildThread. This fixes a bug where when using classes based on GuildThread (ones that most likely inherits from it), because GuildThread inherits from TextGuildChannel the inherited CreateWebhookAsync and the GetChannelWebhooksAsync methods would pass in only the Id (which for normal channels works), but for threads this would always fail as the thread Id would be used as a channel Id and Discord's API does not consider them to be valid channels. As such it is better to attempt to use ParentId (if not null), otherwise use Id (if ParentId is null). Signed-off-by: AraHaan --- NetCord/Rest/RestClient.Webhook.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/NetCord/Rest/RestClient.Webhook.cs b/NetCord/Rest/RestClient.Webhook.cs index 5c6d5afc..67a51446 100644 --- a/NetCord/Rest/RestClient.Webhook.cs +++ b/NetCord/Rest/RestClient.Webhook.cs @@ -4,16 +4,16 @@ namespace NetCord.Rest; public partial class RestClient { - [GenerateAlias([typeof(ForumGuildChannel)], nameof(ForumGuildChannel.Id))] - [GenerateAlias([typeof(TextGuildChannel)], nameof(TextGuildChannel.Id))] + [GenerateAlias([typeof(ForumGuildChannel)], $"{nameof(ForumGuildChannel.ParentId)} ?? {nameof(ForumGuildChannel.Id)}")] + [GenerateAlias([typeof(TextGuildChannel)], $"{nameof(TextGuildChannel.ParentId)} ?? {nameof(TextGuildChannel.Id)}")] public async Task CreateWebhookAsync(ulong channelId, WebhookProperties webhookProperties, RestRequestProperties? properties = null, CancellationToken cancellationToken = default) { using (HttpContent content = new JsonContent(webhookProperties, Serialization.Default.WebhookProperties)) return new(await (await SendRequestAsync(HttpMethod.Post, content, $"/channels/{channelId}/webhooks", null, new(channelId), properties, cancellationToken: cancellationToken).ConfigureAwait(false)).ToObjectAsync(Serialization.Default.JsonWebhook).ConfigureAwait(false), this); } - [GenerateAlias([typeof(ForumGuildChannel)], nameof(ForumGuildChannel.Id))] - [GenerateAlias([typeof(TextGuildChannel)], nameof(TextGuildChannel.Id))] + [GenerateAlias([typeof(ForumGuildChannel)], $"{nameof(ForumGuildChannel.ParentId)} ?? {nameof(ForumGuildChannel.Id)}")] + [GenerateAlias([typeof(TextGuildChannel)], $"{nameof(TextGuildChannel.ParentId)} ?? {nameof(TextGuildChannel.Id)}")] public async Task> GetChannelWebhooksAsync(ulong channelId, RestRequestProperties? properties = null, CancellationToken cancellationToken = default) => (await (await SendRequestAsync(HttpMethod.Get, $"/channels/{channelId}/webhooks", null, new(channelId), properties, cancellationToken: cancellationToken).ConfigureAwait(false)).ToObjectAsync(Serialization.Default.JsonWebhookArray).ConfigureAwait(false)).Select(w => Webhook.CreateFromJson(w, this)).ToArray(); From d36931ab8e628921a9944c7c8c4145756ec4d059 Mon Sep 17 00:00:00 2001 From: AraHaan Date: Tue, 26 May 2026 14:09:43 -0400 Subject: [PATCH 2/3] Leave the existing methods from TextGuildChannel and ForumGuildChannel untouched. Instead we hjide them by generating these methods in GuildThread. --- NetCord/Rest/RestClient.Webhook.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/NetCord/Rest/RestClient.Webhook.cs b/NetCord/Rest/RestClient.Webhook.cs index 67a51446..659e7895 100644 --- a/NetCord/Rest/RestClient.Webhook.cs +++ b/NetCord/Rest/RestClient.Webhook.cs @@ -4,16 +4,22 @@ namespace NetCord.Rest; public partial class RestClient { - [GenerateAlias([typeof(ForumGuildChannel)], $"{nameof(ForumGuildChannel.ParentId)} ?? {nameof(ForumGuildChannel.Id)}")] - [GenerateAlias([typeof(TextGuildChannel)], $"{nameof(TextGuildChannel.ParentId)} ?? {nameof(TextGuildChannel.Id)}")] + // this seems to work but lacks the "new" in the generated member in GuildThread + // to hide the version from TextGuildChannel. + [GenerateAlias([typeof(GuildThread)], $"(ulong){nameof(TextGuildChannel.ParentId)}!")] + [GenerateAlias([typeof(ForumGuildChannel)], nameof(ForumGuildChannel.Id))] + [GenerateAlias([typeof(TextGuildChannel)], nameof(TextGuildChannel.Id))] public async Task CreateWebhookAsync(ulong channelId, WebhookProperties webhookProperties, RestRequestProperties? properties = null, CancellationToken cancellationToken = default) { using (HttpContent content = new JsonContent(webhookProperties, Serialization.Default.WebhookProperties)) return new(await (await SendRequestAsync(HttpMethod.Post, content, $"/channels/{channelId}/webhooks", null, new(channelId), properties, cancellationToken: cancellationToken).ConfigureAwait(false)).ToObjectAsync(Serialization.Default.JsonWebhook).ConfigureAwait(false), this); } - [GenerateAlias([typeof(ForumGuildChannel)], $"{nameof(ForumGuildChannel.ParentId)} ?? {nameof(ForumGuildChannel.Id)}")] - [GenerateAlias([typeof(TextGuildChannel)], $"{nameof(TextGuildChannel.ParentId)} ?? {nameof(TextGuildChannel.Id)}")] + // this seems to work but lacks the "new" in the generated member in GuildThread + // to hide the version from TextGuildChannel. + [GenerateAlias([typeof(GuildThread)], $"(ulong){nameof(TextGuildChannel.ParentId)}!")] + [GenerateAlias([typeof(ForumGuildChannel)], nameof(ForumGuildChannel.Id))] + [GenerateAlias([typeof(TextGuildChannel)], nameof(TextGuildChannel.Id))] public async Task> GetChannelWebhooksAsync(ulong channelId, RestRequestProperties? properties = null, CancellationToken cancellationToken = default) => (await (await SendRequestAsync(HttpMethod.Get, $"/channels/{channelId}/webhooks", null, new(channelId), properties, cancellationToken: cancellationToken).ConfigureAwait(false)).ToObjectAsync(Serialization.Default.JsonWebhookArray).ConfigureAwait(false)).Select(w => Webhook.CreateFromJson(w, this)).ToArray(); From 04ef2dac31dd029374071c81426c660f799aadb8 Mon Sep 17 00:00:00 2001 From: AraHaan Date: Tue, 26 May 2026 17:31:28 -0400 Subject: [PATCH 3/3] Hide original CreateWebhookAsync and GetChannelWebhooksAsync from TextGuildChannel in GuildThread. --- NetCord/Rest/RestClient.Webhook.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/NetCord/Rest/RestClient.Webhook.cs b/NetCord/Rest/RestClient.Webhook.cs index 659e7895..fcf56627 100644 --- a/NetCord/Rest/RestClient.Webhook.cs +++ b/NetCord/Rest/RestClient.Webhook.cs @@ -4,9 +4,7 @@ namespace NetCord.Rest; public partial class RestClient { - // this seems to work but lacks the "new" in the generated member in GuildThread - // to hide the version from TextGuildChannel. - [GenerateAlias([typeof(GuildThread)], $"(ulong){nameof(TextGuildChannel.ParentId)}!")] + [GenerateAlias([typeof(GuildThread)], $"(ulong){nameof(TextGuildChannel.ParentId)}!", Modifiers = ["new"])] [GenerateAlias([typeof(ForumGuildChannel)], nameof(ForumGuildChannel.Id))] [GenerateAlias([typeof(TextGuildChannel)], nameof(TextGuildChannel.Id))] public async Task CreateWebhookAsync(ulong channelId, WebhookProperties webhookProperties, RestRequestProperties? properties = null, CancellationToken cancellationToken = default) @@ -15,9 +13,7 @@ public async Task CreateWebhookAsync(ulong channelId, WebhookPr return new(await (await SendRequestAsync(HttpMethod.Post, content, $"/channels/{channelId}/webhooks", null, new(channelId), properties, cancellationToken: cancellationToken).ConfigureAwait(false)).ToObjectAsync(Serialization.Default.JsonWebhook).ConfigureAwait(false), this); } - // this seems to work but lacks the "new" in the generated member in GuildThread - // to hide the version from TextGuildChannel. - [GenerateAlias([typeof(GuildThread)], $"(ulong){nameof(TextGuildChannel.ParentId)}!")] + [GenerateAlias([typeof(GuildThread)], $"(ulong){nameof(TextGuildChannel.ParentId)}!", Modifiers = ["new"])] [GenerateAlias([typeof(ForumGuildChannel)], nameof(ForumGuildChannel.Id))] [GenerateAlias([typeof(TextGuildChannel)], nameof(TextGuildChannel.Id))] public async Task> GetChannelWebhooksAsync(ulong channelId, RestRequestProperties? properties = null, CancellationToken cancellationToken = default)