From cafa53790e478a7083c591d5ae48b81519f1f590 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Tue, 27 Mar 2018 00:44:13 -0700 Subject: [PATCH 01/20] Fix #995 ICategoryChannel.CategoryID throws NotSupportedException --- src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs | 4 +++- .../Entities/Channels/SocketCategoryChannel.cs | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs index 397e14e768..2a89edb371 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -25,6 +25,8 @@ internal new static RestCategoryChannel Create(BaseDiscordClient discord, IGuild private string DebuggerDisplay => $"{Name} ({Id}, Category)"; // IGuildChannel + ulong? IGuildChannel.CategoryId + => throw new NotSupportedException(); IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => throw new NotSupportedException(); Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs index e7a165c2f1..9986ebf9cf 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs @@ -51,6 +51,8 @@ public override SocketGuildUser GetUser(ulong id) internal new SocketCategoryChannel Clone() => MemberwiseClone() as SocketCategoryChannel; // IGuildChannel + ulong? IGuildChannel.CategoryId + => throw new NotSupportedException(); IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => ImmutableArray.Create>(Users).ToAsyncEnumerable(); Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) From 0613b8d6948ef8486373806ed09ea66485599b81 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Tue, 27 Mar 2018 00:58:32 -0700 Subject: [PATCH 02/20] Add tests --- test/Discord.Net.Tests/Tests.Channels.cs | 31 +++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/test/Discord.Net.Tests/Tests.Channels.cs b/test/Discord.Net.Tests/Tests.Channels.cs index b528ca5fb5..6506dfd9e8 100644 --- a/test/Discord.Net.Tests/Tests.Channels.cs +++ b/test/Discord.Net.Tests/Tests.Channels.cs @@ -1,4 +1,5 @@ using Discord.Rest; +using System; using System.Linq; using System.Threading.Tasks; using Xunit; @@ -140,5 +141,33 @@ private static void CheckVoiceChannels(params RestVoiceChannel[] voiceChannels) Assert.Equal(voice3.Position, 1); Assert.Equal(voice3.UserLimit, 16); } + + [Fact] + public async Task TestChannelCategories() + { + CheckChannelCategories(_client, _guild); + } + + private async static void CheckChannelCategories(DiscordRestClient client, RestGuild guild) + { + // create some channel categories + var cat1 = await guild.CreateCategoryChannelAsync("Cat1"); + var cat2 = await guild.CreateCategoryChannelAsync("Cat2"); + + // check that both CategoryID and GetCategoryID throw NotSupportedException + // because Categories cannot be nested + Assert.Throws(() => + { + var x = cat1.CategoryId; + }); + + Assert.Throws(() => + { + var x = cat2.GetCategoryAsync(); + }); + + + // incomplete test, could use more coverage + } } -} \ No newline at end of file +} From dca85f12df5690bce8df9d90926edc779466375d Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Tue, 27 Mar 2018 01:01:15 -0700 Subject: [PATCH 03/20] change run mode of TestChannelCategories --- test/Discord.Net.Tests/Tests.Channels.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/Discord.Net.Tests/Tests.Channels.cs b/test/Discord.Net.Tests/Tests.Channels.cs index 6506dfd9e8..7c1612a5e1 100644 --- a/test/Discord.Net.Tests/Tests.Channels.cs +++ b/test/Discord.Net.Tests/Tests.Channels.cs @@ -143,9 +143,11 @@ private static void CheckVoiceChannels(params RestVoiceChannel[] voiceChannels) } [Fact] - public async Task TestChannelCategories() + public Task TestChannelCategories() { CheckChannelCategories(_client, _guild); + + return Task.CompletedTask; } private async static void CheckChannelCategories(DiscordRestClient client, RestGuild guild) @@ -166,8 +168,7 @@ private async static void CheckChannelCategories(DiscordRestClient client, RestG var x = cat2.GetCategoryAsync(); }); - - // incomplete test, could use more coverage + // incomplete test, could use more coverage, incluing behavior of nested Text and Voice channels } } } From 6ca9632a628e542e24682a5f5d1cdfb4c25eda46 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Tue, 27 Mar 2018 01:12:47 -0700 Subject: [PATCH 04/20] Add throw for GetCategoryAsync --- src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs | 2 ++ .../Entities/Channels/SocketCategoryChannel.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs index 2a89edb371..bfcfa1a928 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs @@ -27,6 +27,8 @@ internal new static RestCategoryChannel Create(BaseDiscordClient discord, IGuild // IGuildChannel ulong? IGuildChannel.CategoryId => throw new NotSupportedException(); + Task IGuildChannel.GetCategoryAsync() + => throw new NotSupportedException(); IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => throw new NotSupportedException(); Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs index 9986ebf9cf..384620d222 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs @@ -53,6 +53,8 @@ public override SocketGuildUser GetUser(ulong id) // IGuildChannel ulong? IGuildChannel.CategoryId => throw new NotSupportedException(); + Task IGuildChannel.GetCategoryAsync() + => throw new NotSupportedException(); IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => ImmutableArray.Create>(Users).ToAsyncEnumerable(); Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) From f9c67074e0fe8f048f1c708a6120edc05ee0a41b Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Tue, 27 Mar 2018 01:27:49 -0700 Subject: [PATCH 05/20] Add xml doc explaining why exception is thrown --- .../Entities/Channels/RestCategoryChannel.cs | 9 +++++++++ .../Entities/Channels/SocketCategoryChannel.cs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs index bfcfa1a928..bfdf1f6c0d 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs @@ -25,8 +25,17 @@ internal new static RestCategoryChannel Create(BaseDiscordClient discord, IGuild private string DebuggerDisplay => $"{Name} ({Id}, Category)"; // IGuildChannel + + /// + /// Throws a NotSupportedException because Channel Categories cannot be the child of another Channel Category. + /// + /// A NotSupportedException is always thrown because Channel Categories do not support being nested. ulong? IGuildChannel.CategoryId => throw new NotSupportedException(); + /// + /// Throws a NotSupportedException because Channel Categories cannot be the child of another Channel Category. + /// + /// A NotSupportedException is always thrown because Channel Categories do not support being nested. Task IGuildChannel.GetCategoryAsync() => throw new NotSupportedException(); IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs index 384620d222..e53273ec9f 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs @@ -51,8 +51,17 @@ public override SocketGuildUser GetUser(ulong id) internal new SocketCategoryChannel Clone() => MemberwiseClone() as SocketCategoryChannel; // IGuildChannel + + /// + /// Throws a NotSupportedException because Channel Categories cannot be the child of another Channel Category. + /// + /// A NotSupportedException is always thrown because Channel Categories do not support being nested. ulong? IGuildChannel.CategoryId => throw new NotSupportedException(); + /// + /// Throws a NotSupportedException because Channel Categories cannot be the child of another Channel Category. + /// + /// A NotSupportedException is always thrown because Channel Categories do not support being nested. Task IGuildChannel.GetCategoryAsync() => throw new NotSupportedException(); IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) From cb392db30c7525fb351f4069d866f9d49b60a8de Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Tue, 27 Mar 2018 01:45:37 -0700 Subject: [PATCH 06/20] Add test coverage for text and voice channel categories --- test/Discord.Net.Tests/Tests.Channels.cs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/test/Discord.Net.Tests/Tests.Channels.cs b/test/Discord.Net.Tests/Tests.Channels.cs index 7c1612a5e1..512a1ef4e2 100644 --- a/test/Discord.Net.Tests/Tests.Channels.cs +++ b/test/Discord.Net.Tests/Tests.Channels.cs @@ -168,7 +168,29 @@ private async static void CheckChannelCategories(DiscordRestClient client, RestG var x = cat2.GetCategoryAsync(); }); - // incomplete test, could use more coverage, incluing behavior of nested Text and Voice channels + var text1 = await guild.CreateTextChannelAsync("nestedText1"); + var voice1 = await guild.CreateVoiceChannelAsync("nestedVoice1"); + // set the text channel parent to Cat 1 + await text1.ModifyAsync(x => + { + x.CategoryId = cat1.Id; + }); + + await voice1.ModifyAsync(x => + { + x.CategoryId = cat2.Id; + }); + + // these shouldn't throw because they are not channel categories + + // assert that CategoryId works for text channels + Assert.Equal(text1.CategoryId, cat1.Id); + Assert.Equal((await text1.GetCategoryAsync()).Id, cat1.Id); + // and for voice channels + Assert.Equal(voice1.CategoryId, cat2.Id); + Assert.Equal((await voice1.GetCategoryAsync()).Id, cat2.Id); + + // incomplete test, could use more coverage of other methods } } } From 8bb92ccbfe6a7e95df4571c2d0dee80db272fc08 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Wed, 28 Mar 2018 00:44:39 -0700 Subject: [PATCH 07/20] initial implementation of INestedChannel --- .../Entities/Channels/ICategoryChannel.cs | 2 +- .../Entities/Channels/IGuildChannel.cs | 8 ++------ .../Entities/Channels/INestedChannel.cs | 20 +++++++++++++++++++ .../Entities/Channels/ITextChannel.cs | 6 +++--- .../Entities/Channels/RestCategoryChannel.cs | 17 ---------------- .../Entities/Channels/RestGuildChannel.cs | 10 +--------- .../Entities/Channels/RestTextChannel.cs | 11 +++++++++- .../Entities/Channels/RestVoiceChannel.cs | 13 ++++++++++-- .../Entities/Channels/SocketTextChannel.cs | 9 ++++++++- .../Entities/Channels/SocketVoiceChannel.cs | 11 ++++++++-- 10 files changed, 65 insertions(+), 42 deletions(-) create mode 100644 src/Discord.Net.Core/Entities/Channels/INestedChannel.cs diff --git a/src/Discord.Net.Core/Entities/Channels/ICategoryChannel.cs b/src/Discord.Net.Core/Entities/Channels/ICategoryChannel.cs index 0f7f5aa62d..c004cafd5e 100644 --- a/src/Discord.Net.Core/Entities/Channels/ICategoryChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/ICategoryChannel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs b/src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs index c9841cb15c..6514d46cd9 100644 --- a/src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -9,10 +9,6 @@ public interface IGuildChannel : IChannel, IDeletable /// Gets the position of this channel in the guild's channel list, relative to others of the same type. int Position { get; } - /// Gets the parentid (category) of this channel in the guild's channel list. - ulong? CategoryId { get; } - /// Gets the parent channel (category) of this channel. - Task GetCategoryAsync(); /// Gets the guild this channel is a member of. IGuild Guild { get; } /// Gets the id of the guild this channel is a member of. @@ -49,4 +45,4 @@ public interface IGuildChannel : IChannel, IDeletable /// Gets a user in this channel with the provided id. new Task GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); } -} \ No newline at end of file +} diff --git a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs new file mode 100644 index 0000000000..7e9d8fbf03 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// A type of guild channel that can be nested within a category. + /// Contains a CategoryId that is set to the parent category, if it is set. + /// + public interface INestedChannel : IGuildChannel + { + /// Gets the parentid (category) of this channel in the guild's channel list. + ulong? CategoryId { get; } + /// Gets the parent channel (category) of this channel, if it is set. If unset, returns null. + Task GetCategoryAsync(); + } +} diff --git a/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs b/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs index 7c6ec39081..ae15ce2bae 100644 --- a/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs @@ -1,11 +1,11 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; namespace Discord { - public interface ITextChannel : IMessageChannel, IMentionable, IGuildChannel + public interface ITextChannel : IMessageChannel, IMentionable, IGuildChannel, INestedChannel { /// Checks if the channel is NSFW. bool IsNsfw { get; } @@ -28,4 +28,4 @@ public interface ITextChannel : IMessageChannel, IMentionable, IGuildChannel /// Gets the webhooks for this text channel. Task> GetWebhooksAsync(RequestOptions options = null); } -} \ No newline at end of file +} diff --git a/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs index bfdf1f6c0d..321f1f1d24 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs @@ -25,23 +25,6 @@ internal new static RestCategoryChannel Create(BaseDiscordClient discord, IGuild private string DebuggerDisplay => $"{Name} ({Id}, Category)"; // IGuildChannel - - /// - /// Throws a NotSupportedException because Channel Categories cannot be the child of another Channel Category. - /// - /// A NotSupportedException is always thrown because Channel Categories do not support being nested. - ulong? IGuildChannel.CategoryId - => throw new NotSupportedException(); - /// - /// Throws a NotSupportedException because Channel Categories cannot be the child of another Channel Category. - /// - /// A NotSupportedException is always thrown because Channel Categories do not support being nested. - Task IGuildChannel.GetCategoryAsync() - => throw new NotSupportedException(); - IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) - => throw new NotSupportedException(); - Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) - => throw new NotSupportedException(); Task IGuildChannel.CreateInviteAsync(int? maxAge, int? maxUses, bool isTemporary, bool isUnique, RequestOptions options) => throw new NotSupportedException(); Task> IGuildChannel.GetInvitesAsync(RequestOptions options) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs index 026d03cc83..8bddcff09e 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -16,7 +16,6 @@ public class RestGuildChannel : RestChannel, IGuildChannel, IUpdateable internal IGuild Guild { get; } public string Name { get; private set; } public int Position { get; private set; } - public ulong? CategoryId { get; private set; } public ulong GuildId => Guild.Id; internal RestGuildChannel(BaseDiscordClient discord, IGuild guild, ulong id) @@ -64,13 +63,6 @@ public async Task ModifyAsync(Action func, RequestOption public Task DeleteAsync(RequestOptions options = null) => ChannelHelper.DeleteAsync(this, Discord, options); - public async Task GetCategoryAsync() - { - if (CategoryId.HasValue) - return (await Guild.GetChannelAsync(CategoryId.Value).ConfigureAwait(false)) as ICategoryChannel; - return null; - } - public OverwritePermissions? GetPermissionOverwrite(IUser user) { for (int i = 0; i < _overwrites.Length; i++) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs index 600b197d61..18af4939ac 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs @@ -9,9 +9,10 @@ namespace Discord.Rest { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class RestTextChannel : RestGuildChannel, IRestMessageChannel, ITextChannel + public class RestTextChannel : RestGuildChannel, IRestMessageChannel, ITextChannel, INestedChannel { public string Topic { get; private set; } + public ulong? CategoryId { get; private set; } public string Mention => MentionUtils.MentionChannel(Id); @@ -168,5 +169,13 @@ IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mo else return AsyncEnumerable.Empty>(); } + + // INestedChannel + async Task INestedChannel.GetCategoryAsync() + { + if (CategoryId.HasValue) + return (await Guild.GetChannelAsync(CategoryId.Value).ConfigureAwait(false)) as ICategoryChannel; + return null; + } } } diff --git a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs index 300ebd08d5..53a28eaeea 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs @@ -1,4 +1,4 @@ -using Discord.Audio; +using Discord.Audio; using System; using System.Collections.Generic; using System.Diagnostics; @@ -9,10 +9,11 @@ namespace Discord.Rest { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class RestVoiceChannel : RestGuildChannel, IVoiceChannel, IRestAudioChannel + public class RestVoiceChannel : RestGuildChannel, IVoiceChannel, IRestAudioChannel, INestedChannel { public int Bitrate { get; private set; } public int? UserLimit { get; private set; } + public ulong? CategoryId { get; private set; } internal RestVoiceChannel(BaseDiscordClient discord, IGuild guild, ulong id) : base(discord, guild, id) @@ -48,5 +49,13 @@ Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOpt => Task.FromResult(null); IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => AsyncEnumerable.Empty>(); + + // INestedChannel + async Task INestedChannel.GetCategoryAsync() + { + if (CategoryId.HasValue) + return (await Guild.GetChannelAsync(CategoryId.Value).ConfigureAwait(false)) as ICategoryChannel; + return null; + } } } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs index ec7615b55e..b94ded5fbd 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs @@ -11,11 +11,14 @@ namespace Discord.WebSocket { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class SocketTextChannel : SocketGuildChannel, ITextChannel, ISocketMessageChannel + public class SocketTextChannel : SocketGuildChannel, ITextChannel, ISocketMessageChannel, INestedChannel { private readonly MessageCache _messages; public string Topic { get; private set; } + public ulong? CategoryId { get; private set; } + public ICategoryChannel Category + => CategoryId.HasValue ? Guild.GetChannel(CategoryId.Value) as ICategoryChannel : null; private bool _nsfw; public bool IsNsfw => _nsfw || ChannelHelper.IsNsfw(this); @@ -164,5 +167,9 @@ async Task IMessageChannel.SendMessageAsync(string text, bool isTT => await SendMessageAsync(text, isTTS, embed, options).ConfigureAwait(false); IDisposable IMessageChannel.EnterTypingState(RequestOptions options) => EnterTypingState(options); + + // INestedChannel + Task INestedChannel.GetCategoryAsync() + => Task.FromResult(Category); } } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs index e8a6698458..a8ec9457aa 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs @@ -1,4 +1,4 @@ -using Discord.Audio; +using Discord.Audio; using Discord.Rest; using System; using System.Collections.Generic; @@ -11,10 +11,13 @@ namespace Discord.WebSocket { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class SocketVoiceChannel : SocketGuildChannel, IVoiceChannel, ISocketAudioChannel + public class SocketVoiceChannel : SocketGuildChannel, IVoiceChannel, ISocketAudioChannel, INestedChannel { public int Bitrate { get; private set; } public int? UserLimit { get; private set; } + public ulong? CategoryId { get; private set; } + public ICategoryChannel Category + => CategoryId.HasValue ? Guild.GetChannel(CategoryId.Value) as ICategoryChannel : null; public override IReadOnlyCollection Users => Guild.Users.Where(x => x.VoiceChannel?.Id == Id).ToImmutableArray(); @@ -61,5 +64,9 @@ Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOpt => Task.FromResult(GetUser(id)); IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => ImmutableArray.Create>(Users).ToAsyncEnumerable(); + + // INestedChannel + Task INestedChannel.GetCategoryAsync() + => Task.FromResult(Category); } } From de84fcf4930773db83b140b16e05e4215a9039ec Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Wed, 28 Mar 2018 01:43:02 -0700 Subject: [PATCH 08/20] more implementation of INestedChannel design --- .../Entities/Channels/INestedChannel.cs | 4 ---- .../Entities/Channels/ChannelHelper.cs | 10 ++++++++++ .../Entities/Channels/RestTextChannel.cs | 8 ++++++-- .../Entities/Channels/RestVoiceChannel.cs | 3 +++ .../Channels/SocketCategoryChannel.cs | 15 +-------------- .../Entities/Channels/SocketGuildChannel.cs | 13 +++---------- .../Entities/Channels/SocketTextChannel.cs | 6 +++++- .../Entities/Channels/SocketVoiceChannel.cs | 7 +++++-- test/Discord.Net.Tests/Tests.Channels.cs | 19 +++++++------------ 9 files changed, 40 insertions(+), 45 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs index 7e9d8fbf03..4082bfbb2b 100644 --- a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; namespace Discord diff --git a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs index 6784f7f6a9..e82d0fecf4 100644 --- a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs +++ b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs @@ -313,6 +313,16 @@ public static async Task> GetWebhooksAsync(ITex return models.Select(x => RestWebhook.Create(client, channel, x)) .ToImmutableArray(); } + // Categories + public static async Task GetCategoryAsync(INestedChannel channel, BaseDiscordClient client, RequestOptions options) + { + // if no category id specified, return null + if (!channel.CategoryId.HasValue) + return null; + // CategoryId will contain a value here + var model = await client.ApiClient.GetChannelAsync(channel.CategoryId.Value, options).ConfigureAwait(false); + return RestCategoryChannel.Create(client, model) as ICategoryChannel; + } //Helpers private static IUser GetAuthor(BaseDiscordClient client, IGuild guild, UserModel model, ulong? webhookId) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs index 18af4939ac..d597efa9aa 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs @@ -32,7 +32,7 @@ internal new static RestTextChannel Create(BaseDiscordClient discord, IGuild gui internal override void Update(Model model) { base.Update(model); - + CategoryId = model.CategoryId; Topic = model.Topic.Value; _nsfw = model.Nsfw.GetValueOrDefault(); } @@ -47,7 +47,7 @@ public Task GetUserAsync(ulong id, RequestOptions options = null) => ChannelHelper.GetUserAsync(this, Guild, Discord, id, options); public IAsyncEnumerable> GetUsersAsync(RequestOptions options = null) => ChannelHelper.GetUsersAsync(this, Guild, Discord, null, null, options); - + public Task GetMessageAsync(ulong id, RequestOptions options = null) => ChannelHelper.GetMessageAsync(this, Discord, id, options); public IAsyncEnumerable> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) @@ -84,6 +84,9 @@ public Task GetWebhookAsync(ulong id, RequestOptions options = null => ChannelHelper.GetWebhookAsync(this, Discord, id, options); public Task> GetWebhooksAsync(RequestOptions options = null) => ChannelHelper.GetWebhooksAsync(this, Discord, options); + + public Task GetCategoryAsync(RequestOptions options = null) + => ChannelHelper.GetCategoryAsync(this, Discord, options); private string DebuggerDisplay => $"{Name} ({Id}, Text)"; @@ -110,6 +113,7 @@ IAsyncEnumerable> IMessageChannel.GetMessagesAsync else return AsyncEnumerable.Empty>(); } + IAsyncEnumerable> IMessageChannel.GetMessagesAsync(ulong fromMessageId, Direction dir, int limit, CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs index 53a28eaeea..05bc480b54 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs @@ -39,6 +39,9 @@ public async Task ModifyAsync(Action func, RequestOption Update(model); } + public Task GetCategoryAsync(RequestOptions options = null) + => ChannelHelper.GetCategoryAsync(this, Discord, options); + private string DebuggerDisplay => $"{Name} ({Id}, Voice)"; //IAudioChannel diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs index e53273ec9f..7b6619be6b 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs @@ -20,7 +20,7 @@ public override IReadOnlyCollection Users ChannelPermission.ViewChannel)).ToImmutableArray(); public IReadOnlyCollection Channels - => Guild.Channels.Where(x => x.CategoryId == Id).ToImmutableArray(); + => Guild.Channels.Where(x => x is INestedChannel && (x as INestedChannel).CategoryId == Id).ToImmutableArray(); internal SocketCategoryChannel(DiscordSocketClient discord, ulong id, SocketGuild guild) : base(discord, id, guild) @@ -51,19 +51,6 @@ public override SocketGuildUser GetUser(ulong id) internal new SocketCategoryChannel Clone() => MemberwiseClone() as SocketCategoryChannel; // IGuildChannel - - /// - /// Throws a NotSupportedException because Channel Categories cannot be the child of another Channel Category. - /// - /// A NotSupportedException is always thrown because Channel Categories do not support being nested. - ulong? IGuildChannel.CategoryId - => throw new NotSupportedException(); - /// - /// Throws a NotSupportedException because Channel Categories cannot be the child of another Channel Category. - /// - /// A NotSupportedException is always thrown because Channel Categories do not support being nested. - Task IGuildChannel.GetCategoryAsync() - => throw new NotSupportedException(); IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => ImmutableArray.Create>(Users).ToAsyncEnumerable(); Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs index 2163daf554..bfcffa35f1 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs @@ -1,4 +1,4 @@ -using Discord.Rest; +using Discord.Rest; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -16,10 +16,7 @@ public class SocketGuildChannel : SocketChannel, IGuildChannel public SocketGuild Guild { get; } public string Name { get; private set; } - public int Position { get; private set; } - public ulong? CategoryId { get; private set; } - public ICategoryChannel Category - => CategoryId.HasValue ? Guild.GetChannel(CategoryId.Value) as ICategoryChannel : null; + public int Position { get; private set; } public IReadOnlyCollection PermissionOverwrites => _overwrites; public new virtual IReadOnlyCollection Users => ImmutableArray.Create(); @@ -48,8 +45,7 @@ internal override void Update(ClientState state, Model model) { Name = model.Name.Value; Position = model.Position.Value; - CategoryId = model.CategoryId; - + var overwrites = model.PermissionOverwrites.Value; var newOverwrites = ImmutableArray.CreateBuilder(overwrites.Length); for (int i = 0; i < overwrites.Length; i++) @@ -135,9 +131,6 @@ public async Task CreateInviteAsync(int? maxAge = 86400, int IGuild IGuildChannel.Guild => Guild; ulong IGuildChannel.GuildId => Guild.Id; - Task IGuildChannel.GetCategoryAsync() - => Task.FromResult(Category); - async Task> IGuildChannel.GetInvitesAsync(RequestOptions options) => await GetInvitesAsync(options).ConfigureAwait(false); async Task IGuildChannel.CreateInviteAsync(int? maxAge, int? maxUses, bool isTemporary, bool isUnique, RequestOptions options) diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs index b94ded5fbd..54d8e53ee4 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs @@ -45,7 +45,7 @@ internal new static SocketTextChannel Create(SocketGuild guild, ClientState stat internal override void Update(ClientState state, Model model) { base.Update(state, model); - + CategoryId = model.CategoryId; Topic = model.Topic.Value; _nsfw = model.Nsfw.GetValueOrDefault(); } @@ -124,6 +124,10 @@ public Task GetWebhookAsync(ulong id, RequestOptions options = null public Task> GetWebhooksAsync(RequestOptions options = null) => ChannelHelper.GetWebhooksAsync(this, Discord, options); + // Categories + public Task GetCategoryAsync(RequestOptions options = null) + => ChannelHelper.GetCategoryAsync(this, Discord, options); + private string DebuggerDisplay => $"{Name} ({Id}, Text)"; internal new SocketTextChannel Clone() => MemberwiseClone() as SocketTextChannel; diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs index a8ec9457aa..45d68bd852 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs @@ -35,7 +35,7 @@ internal new static SocketVoiceChannel Create(SocketGuild guild, ClientState sta 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; } @@ -55,7 +55,10 @@ public override SocketGuildUser GetUser(ulong id) return user; return null; } - + + public Task GetCategoryAsync(RequestOptions options = null) + => ChannelHelper.GetCategoryAsync(this, Discord, options); + private string DebuggerDisplay => $"{Name} ({Id}, Voice)"; internal new SocketVoiceChannel Clone() => MemberwiseClone() as SocketVoiceChannel; diff --git a/test/Discord.Net.Tests/Tests.Channels.cs b/test/Discord.Net.Tests/Tests.Channels.cs index 512a1ef4e2..407241f8cd 100644 --- a/test/Discord.Net.Tests/Tests.Channels.cs +++ b/test/Discord.Net.Tests/Tests.Channels.cs @@ -156,18 +156,6 @@ private async static void CheckChannelCategories(DiscordRestClient client, RestG var cat1 = await guild.CreateCategoryChannelAsync("Cat1"); var cat2 = await guild.CreateCategoryChannelAsync("Cat2"); - // check that both CategoryID and GetCategoryID throw NotSupportedException - // because Categories cannot be nested - Assert.Throws(() => - { - var x = cat1.CategoryId; - }); - - Assert.Throws(() => - { - var x = cat2.GetCategoryAsync(); - }); - var text1 = await guild.CreateTextChannelAsync("nestedText1"); var voice1 = await guild.CreateVoiceChannelAsync("nestedVoice1"); // set the text channel parent to Cat 1 @@ -185,10 +173,17 @@ private async static void CheckChannelCategories(DiscordRestClient client, RestG // assert that CategoryId works for text channels Assert.Equal(text1.CategoryId, cat1.Id); + Assert.True(text1 is INestedChannel); + Assert.Equal((await (text1 as INestedChannel).GetCategoryAsync()).Id, cat1.Id); Assert.Equal((await text1.GetCategoryAsync()).Id, cat1.Id); + Assert.Equal(text1.CategoryId, cat1.Id); + // and for voice channels Assert.Equal(voice1.CategoryId, cat2.Id); + Assert.True(voice1 is INestedChannel); + Assert.Equal((await (voice1 as INestedChannel).GetCategoryAsync()).Id, cat2.Id); Assert.Equal((await voice1.GetCategoryAsync()).Id, cat2.Id); + Assert.Equal(voice1.CategoryId, cat1.Id); // incomplete test, could use more coverage of other methods } From ba2a58914dda95e38fc198994fcbfefc297b875b Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Wed, 28 Mar 2018 02:50:28 -0700 Subject: [PATCH 09/20] Add case in RestChannel Create for Category type --- src/Discord.Net.Rest/Entities/Channels/RestChannel.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestChannel.cs index 04cc5a9378..5860d82839 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestChannel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -24,6 +24,8 @@ internal static RestChannel Create(BaseDiscordClient discord, Model model) case ChannelType.DM: case ChannelType.Group: return CreatePrivate(discord, model) as RestChannel; + case ChannelType.Category: + return RestCategoryChannel.Create(discord, new RestGuild(discord, model.GuildId.Value), model); default: return new RestChannel(discord, model.Id); } From 52739e4838e3fecaed780886da79bea607c33f33 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Thu, 29 Mar 2018 20:18:18 -0700 Subject: [PATCH 10/20] set the CategoryID for RestVoiceChannel --- src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs index 05bc480b54..870876ee00 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs @@ -28,7 +28,7 @@ internal new static RestVoiceChannel Create(BaseDiscordClient discord, IGuild gu internal override void Update(Model model) { base.Update(model); - + CategoryId = model.CategoryId; Bitrate = model.Bitrate.Value; UserLimit = model.UserLimit.Value != 0 ? model.UserLimit.Value : (int?)null; } From bf7c4dc8a721339e910a28c1c6532e73b1e77f19 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Thu, 29 Mar 2018 20:20:11 -0700 Subject: [PATCH 11/20] rewrite channel category tests to work with existing pattern --- test/Discord.Net.Tests/Tests.Channels.cs | 87 ++++++++++++++++-------- 1 file changed, 57 insertions(+), 30 deletions(-) diff --git a/test/Discord.Net.Tests/Tests.Channels.cs b/test/Discord.Net.Tests/Tests.Channels.cs index 407241f8cd..46a3a81815 100644 --- a/test/Discord.Net.Tests/Tests.Channels.cs +++ b/test/Discord.Net.Tests/Tests.Channels.cs @@ -16,17 +16,28 @@ internal static async Task Migration_CreateTextChannels(DiscordRestClient client var text4 = await guild.CreateTextChannelAsync("text4"); var text5 = await guild.CreateTextChannelAsync("text5"); + // create a channel category + var cat1 = await guild.CreateCategoryChannelAsync("cat1"); + + if (text1 == null) + { + // the guild did not have a default channel, so make a new one + text1 = await guild.CreateTextChannelAsync("default"); + } + //Modify #general await text1.ModifyAsync(x => { x.Name = "text1"; x.Position = 1; x.Topic = "Topic1"; + x.CategoryId = cat1.Id; }); await text2.ModifyAsync(x => { x.Position = 2; + x.CategoryId = cat1.Id; }); await text3.ModifyAsync(x => { @@ -90,10 +101,13 @@ internal static async Task Migration_CreateVoiceChannels(DiscordRestClient clien var voice2 = await guild.CreateVoiceChannelAsync("voice2"); var voice3 = await guild.CreateVoiceChannelAsync("voice3"); + var cat2 = await guild.CreateCategoryChannelAsync("cat2"); + await voice1.ModifyAsync(x => { x.Bitrate = 96000; x.Position = 1; + x.CategoryId = cat2.Id; }); await voice2.ModifyAsync(x => { @@ -104,6 +118,7 @@ internal static async Task Migration_CreateVoiceChannels(DiscordRestClient clien x.Bitrate = 8000; x.Position = 1; x.UserLimit = 16; + x.CategoryId = cat2.Id; }); CheckVoiceChannels(voice1, voice2, voice3); @@ -143,49 +158,61 @@ private static void CheckVoiceChannels(params RestVoiceChannel[] voiceChannels) } [Fact] - public Task TestChannelCategories() + public async Task TestChannelCategories() { - CheckChannelCategories(_client, _guild); + // (await _guild.GetVoiceChannelsAsync()).ToArray() + var channels = await _guild.GetCategoryChannelsAsync(); - return Task.CompletedTask; + await CheckChannelCategories(channels.ToArray(), (await _guild.GetChannelsAsync()).ToArray()); } - private async static void CheckChannelCategories(DiscordRestClient client, RestGuild guild) + private async Task CheckChannelCategories(RestCategoryChannel[] categories, RestGuildChannel[] allChannels) { - // create some channel categories - var cat1 = await guild.CreateCategoryChannelAsync("Cat1"); - var cat2 = await guild.CreateCategoryChannelAsync("Cat2"); + // 2 categories + Assert.Equal(categories.Length, 2); - var text1 = await guild.CreateTextChannelAsync("nestedText1"); - var voice1 = await guild.CreateVoiceChannelAsync("nestedVoice1"); - // set the text channel parent to Cat 1 - await text1.ModifyAsync(x => - { - x.CategoryId = cat1.Id; - }); + var cat1 = categories.Where(x => x.Name == "cat1").FirstOrDefault(); + var cat2 = categories.Where(x => x.Name == "cat2").FirstOrDefault(); - await voice1.ModifyAsync(x => - { - x.CategoryId = cat2.Id; - }); + Assert.NotNull(cat1); + Assert.NotNull(cat2); - // these shouldn't throw because they are not channel categories + // get text1, text2, ensure they have category id == cat1 + var text1 = allChannels.Where(x => x.Name == "text1").FirstOrDefault() as RestTextChannel; + var text2 = allChannels.Where(x => x.Name == "text2").FirstOrDefault() as RestTextChannel; - // assert that CategoryId works for text channels - Assert.Equal(text1.CategoryId, cat1.Id); - Assert.True(text1 is INestedChannel); - Assert.Equal((await (text1 as INestedChannel).GetCategoryAsync()).Id, cat1.Id); - Assert.Equal((await text1.GetCategoryAsync()).Id, cat1.Id); + Assert.NotNull(text1); + Assert.NotNull(text2); + + // check that CategoryID and .GetCategoryAsync work correctly + // for both of the text channels Assert.Equal(text1.CategoryId, cat1.Id); + var text1Cat = await text1.GetCategoryAsync(); + Assert.Equal(text1Cat.Id, cat1.Id); + Assert.Equal(text1Cat.Name, cat1.Name); + + Assert.Equal(text2.CategoryId, cat1.Id); + var text2Cat = await text2.GetCategoryAsync(); + Assert.Equal(text2Cat.Id, cat1.Id); + Assert.Equal(text2Cat.Name, cat1.Name); + + // do the same for the voice channels + var voice1 = allChannels.Where(x => x.Name == "voice1").FirstOrDefault() as RestVoiceChannel; + var voice3 = allChannels.Where(x => x.Name == "voice3").FirstOrDefault() as RestVoiceChannel; - // and for voice channels + Assert.NotNull(voice1); + Assert.NotNull(voice3); + Assert.Equal(voice1.CategoryId, cat2.Id); - Assert.True(voice1 is INestedChannel); - Assert.Equal((await (voice1 as INestedChannel).GetCategoryAsync()).Id, cat2.Id); - Assert.Equal((await voice1.GetCategoryAsync()).Id, cat2.Id); - Assert.Equal(voice1.CategoryId, cat1.Id); + var voice1Cat = await voice1.GetCategoryAsync(); + Assert.Equal(voice1Cat.Id, cat2.Id); + Assert.Equal(voice1Cat.Name, cat2.Name); + + Assert.Equal(voice3.CategoryId, cat2.Id); + var voice3Cat = await voice3.GetCategoryAsync(); + Assert.Equal(voice3Cat.Id, cat2.Id); + Assert.Equal(voice3Cat.Name, cat2.Name); - // incomplete test, could use more coverage of other methods } } } From 3ed1148ec88c9808334406519d8bc9d8d13bab5c Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Thu, 29 Mar 2018 21:36:09 -0700 Subject: [PATCH 12/20] remove outdated todo --- src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs index 8bddcff09e..7355e3673d 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs @@ -34,7 +34,6 @@ internal static RestGuildChannel Create(BaseDiscordClient discord, IGuild guild, case ChannelType.Category: return RestCategoryChannel.Create(discord, guild, model); default: - // TODO: Channel categories return new RestGuildChannel(discord, guild, model.Id); } } From bb51b660d662b95b8524a05aa035f2deca892356 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Tue, 3 Apr 2018 21:45:35 -0700 Subject: [PATCH 13/20] Make IVoiceChannel implement INestedChannel --- src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs b/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs index e2a2ad8ebf..3f9ff953b2 100644 --- a/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs @@ -1,9 +1,9 @@ -using System; +using System; using System.Threading.Tasks; namespace Discord { - public interface IVoiceChannel : IGuildChannel, IAudioChannel + public interface IVoiceChannel : IGuildChannel, IAudioChannel, INestedChannel { /// Gets the bitrate, in bits per second, clients in this voice channel are requested to use. int Bitrate { get; } @@ -13,4 +13,4 @@ public interface IVoiceChannel : IGuildChannel, IAudioChannel /// Modifies this voice channel. Task ModifyAsync(Action func, RequestOptions options = null); } -} \ No newline at end of file +} From f6f8576ccdbf105d8378bb10cd4000dec966084f Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Tue, 3 Apr 2018 21:47:10 -0700 Subject: [PATCH 14/20] remove redundant interface implementation --- src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs | 2 +- src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs | 2 +- .../Entities/Channels/SocketTextChannel.cs | 2 +- .../Entities/Channels/SocketVoiceChannel.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs index d597efa9aa..a9d07ae21b 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs @@ -9,7 +9,7 @@ namespace Discord.Rest { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class RestTextChannel : RestGuildChannel, IRestMessageChannel, ITextChannel, INestedChannel + public class RestTextChannel : RestGuildChannel, IRestMessageChannel, ITextChannel { public string Topic { get; private set; } public ulong? CategoryId { get; private set; } diff --git a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs index 870876ee00..a21c504450 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs @@ -9,7 +9,7 @@ namespace Discord.Rest { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class RestVoiceChannel : RestGuildChannel, IVoiceChannel, IRestAudioChannel, INestedChannel + public class RestVoiceChannel : RestGuildChannel, IVoiceChannel, IRestAudioChannel { public int Bitrate { get; private set; } public int? UserLimit { get; private set; } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs index 54d8e53ee4..bf20fe863a 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs @@ -11,7 +11,7 @@ namespace Discord.WebSocket { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class SocketTextChannel : SocketGuildChannel, ITextChannel, ISocketMessageChannel, INestedChannel + public class SocketTextChannel : SocketGuildChannel, ITextChannel, ISocketMessageChannel { private readonly MessageCache _messages; diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs index 45d68bd852..50f61d135f 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs @@ -11,7 +11,7 @@ namespace Discord.WebSocket { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class SocketVoiceChannel : SocketGuildChannel, IVoiceChannel, ISocketAudioChannel, INestedChannel + public class SocketVoiceChannel : SocketGuildChannel, IVoiceChannel, ISocketAudioChannel { public int Bitrate { get; private set; } public int? UserLimit { get; private set; } From 252932c6329a2b01f77fd70e998e26e94c0b493d Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Tue, 3 Apr 2018 21:58:24 -0700 Subject: [PATCH 15/20] Add c#7 feature from feedback --- .../Entities/Channels/SocketCategoryChannel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs index 7b6619be6b..74ca02dba4 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs @@ -20,7 +20,7 @@ public override IReadOnlyCollection Users ChannelPermission.ViewChannel)).ToImmutableArray(); public IReadOnlyCollection Channels - => Guild.Channels.Where(x => x is INestedChannel && (x as INestedChannel).CategoryId == Id).ToImmutableArray(); + => Guild.Channels.Where(x => x is INestedChannel nestedChannel && nestedChannel.CategoryId == Id).ToImmutableArray(); internal SocketCategoryChannel(DiscordSocketClient discord, ulong id, SocketGuild guild) : base(discord, id, guild) From e9ef02e8f46824d04d97fdce760b9a65bded9211 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Tue, 3 Apr 2018 23:56:53 -0700 Subject: [PATCH 16/20] Remove redundant GetCategoryAsync methods from socket entities --- .../Entities/Channels/SocketTextChannel.cs | 4 ---- .../Entities/Channels/SocketVoiceChannel.cs | 3 --- 2 files changed, 7 deletions(-) diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs index bf20fe863a..8a9398e274 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs @@ -124,10 +124,6 @@ public Task GetWebhookAsync(ulong id, RequestOptions options = null public Task> GetWebhooksAsync(RequestOptions options = null) => ChannelHelper.GetWebhooksAsync(this, Discord, options); - // Categories - public Task GetCategoryAsync(RequestOptions options = null) - => ChannelHelper.GetCategoryAsync(this, Discord, options); - private string DebuggerDisplay => $"{Name} ({Id}, Text)"; internal new SocketTextChannel Clone() => MemberwiseClone() as SocketTextChannel; diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs index 50f61d135f..8029697fa0 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs @@ -56,9 +56,6 @@ public override SocketGuildUser GetUser(ulong id) return null; } - public Task GetCategoryAsync(RequestOptions options = null) - => ChannelHelper.GetCategoryAsync(this, Discord, options); - private string DebuggerDisplay => $"{Name} ({Id}, Voice)"; internal new SocketVoiceChannel Clone() => MemberwiseClone() as SocketVoiceChannel; From bb6b879fb2dae7c2bc9a9614d0f017d82db66873 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Tue, 3 Apr 2018 23:59:10 -0700 Subject: [PATCH 17/20] Added configureawait to async methods --- src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs index a9d07ae21b..dbf4eb6884 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs @@ -92,11 +92,11 @@ public Task GetCategoryAsync(RequestOptions options = null) //ITextChannel async Task ITextChannel.CreateWebhookAsync(string name, Stream avatar, RequestOptions options) - => await CreateWebhookAsync(name, avatar, options); + => await CreateWebhookAsync(name, avatar, options).ConfigureAwait(false); async Task ITextChannel.GetWebhookAsync(ulong id, RequestOptions options) - => await GetWebhookAsync(id, options); + => await GetWebhookAsync(id, options).ConfigureAwait(false); async Task> ITextChannel.GetWebhooksAsync(RequestOptions options) - => await GetWebhooksAsync(options); + => await GetWebhooksAsync(options).ConfigureAwait(false); //IMessageChannel async Task IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) From cd37d63be41069aa84868107d5604ce17b74ddd1 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Wed, 4 Apr 2018 00:08:10 -0700 Subject: [PATCH 18/20] change signature of interface GetCategoryAsync --- src/Discord.Net.Core/Entities/Channels/INestedChannel.cs | 2 +- src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs | 4 ++-- src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs | 4 ++-- .../Entities/Channels/SocketTextChannel.cs | 2 +- .../Entities/Channels/SocketVoiceChannel.cs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs index 4082bfbb2b..c8d2bcaafb 100644 --- a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs @@ -11,6 +11,6 @@ public interface INestedChannel : IGuildChannel /// Gets the parentid (category) of this channel in the guild's channel list. ulong? CategoryId { get; } /// Gets the parent channel (category) of this channel, if it is set. If unset, returns null. - Task GetCategoryAsync(); + Task GetCategoryAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); } } diff --git a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs index dbf4eb6884..61b587cde2 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs @@ -175,10 +175,10 @@ IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mo } // INestedChannel - async Task INestedChannel.GetCategoryAsync() + async Task INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) { if (CategoryId.HasValue) - return (await Guild.GetChannelAsync(CategoryId.Value).ConfigureAwait(false)) as ICategoryChannel; + return (await Guild.GetChannelAsync(CategoryId.Value, mode, options).ConfigureAwait(false)) as ICategoryChannel; return null; } } diff --git a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs index a21c504450..342651e872 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs @@ -54,10 +54,10 @@ IAsyncEnumerable> IGuildChannel.GetUsersAsync(Ca => AsyncEnumerable.Empty>(); // INestedChannel - async Task INestedChannel.GetCategoryAsync() + async Task INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) { if (CategoryId.HasValue) - return (await Guild.GetChannelAsync(CategoryId.Value).ConfigureAwait(false)) as ICategoryChannel; + return (await Guild.GetChannelAsync(CategoryId.Value, mode, options).ConfigureAwait(false)) as ICategoryChannel; return null; } } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs index 8a9398e274..0b01f34c38 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs @@ -169,7 +169,7 @@ IDisposable IMessageChannel.EnterTypingState(RequestOptions options) => EnterTypingState(options); // INestedChannel - Task INestedChannel.GetCategoryAsync() + Task INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) => Task.FromResult(Category); } } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs index 8029697fa0..349621fac3 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs @@ -66,7 +66,7 @@ IAsyncEnumerable> IGuildChannel.GetUsersAsync(Ca => ImmutableArray.Create>(Users).ToAsyncEnumerable(); // INestedChannel - Task INestedChannel.GetCategoryAsync() + Task INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) => Task.FromResult(Category); } } From 36f49e1d25d17434331762ac27ed6833c56022f7 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Wed, 4 Apr 2018 02:38:29 -0700 Subject: [PATCH 19/20] Add check for cachemode in rest channel GetCategory --- src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs | 2 +- src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs index 61b587cde2..9b72fb3661 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs @@ -177,7 +177,7 @@ IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mo // INestedChannel async Task INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) { - if (CategoryId.HasValue) + if (CategoryId.HasValue && mode == CacheMode.AllowDownload) return (await Guild.GetChannelAsync(CategoryId.Value, mode, options).ConfigureAwait(false)) as ICategoryChannel; return null; } diff --git a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs index 342651e872..a2bead45fe 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs @@ -56,7 +56,7 @@ IAsyncEnumerable> IGuildChannel.GetUsersAsync(Ca // INestedChannel async Task INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) { - if (CategoryId.HasValue) + if (CategoryId.HasValue && mode == CacheMode.AllowDownload) return (await Guild.GetChannelAsync(CategoryId.Value, mode, options).ConfigureAwait(false)) as ICategoryChannel; return null; } From 3cf417a112b226d8350a763ca2fabfa8d4baffb2 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Thu, 5 Apr 2018 14:43:42 -0700 Subject: [PATCH 20/20] remove redundant IGuildChannel interface from ITextChannel and IVoiceChannel --- src/Discord.Net.Core/Entities/Channels/ITextChannel.cs | 2 +- src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs b/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs index ae15ce2bae..2aa070b03d 100644 --- a/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs @@ -5,7 +5,7 @@ namespace Discord { - public interface ITextChannel : IMessageChannel, IMentionable, IGuildChannel, INestedChannel + public interface ITextChannel : IMessageChannel, IMentionable, INestedChannel { /// Checks if the channel is NSFW. bool IsNsfw { get; } diff --git a/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs b/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs index 3f9ff953b2..2e345bfda2 100644 --- a/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs @@ -3,7 +3,7 @@ namespace Discord { - public interface IVoiceChannel : IGuildChannel, IAudioChannel, INestedChannel + public interface IVoiceChannel : INestedChannel, IAudioChannel { /// Gets the bitrate, in bits per second, clients in this voice channel are requested to use. int Bitrate { get; }