From de84fcf4930773db83b140b16e05e4215a9039ec Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Wed, 28 Mar 2018 01:43:02 -0700 Subject: [PATCH] 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 7e9d8fbf0..4082bfbb2 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 6784f7f6a..e82d0fecf 100644 --- a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs +++ b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs @@ -313,6 +313,16 @@ namespace Discord.Rest 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 18af4939a..d597efa9a 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs @@ -32,7 +32,7 @@ namespace Discord.Rest internal override void Update(Model model) { base.Update(model); - + CategoryId = model.CategoryId; Topic = model.Topic.Value; _nsfw = model.Nsfw.GetValueOrDefault(); } @@ -47,7 +47,7 @@ namespace Discord.Rest => 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 @@ namespace Discord.Rest => 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 @@ namespace Discord.Rest 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 53a28eaee..05bc480b5 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs @@ -39,6 +39,9 @@ namespace Discord.Rest 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 e53273ec9..7b6619be6 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs @@ -20,7 +20,7 @@ namespace Discord.WebSocket 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 @@ namespace Discord.WebSocket 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 2163daf55..bfcffa35f 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 @@ namespace Discord.WebSocket 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 @@ namespace Discord.WebSocket { 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 @@ namespace Discord.WebSocket 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 b94ded5fb..54d8e53ee 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs @@ -45,7 +45,7 @@ namespace Discord.WebSocket 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 @@ namespace Discord.WebSocket 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 a8ec9457a..45d68bd85 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs @@ -35,7 +35,7 @@ namespace Discord.WebSocket internal override void Update(ClientState state, Model model) { base.Update(state, model); - + CategoryId = model.CategoryId; Bitrate = model.Bitrate.Value; UserLimit = model.UserLimit.Value != 0 ? model.UserLimit.Value : (int?)null; } @@ -55,7 +55,10 @@ namespace Discord.WebSocket 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 512a1ef4e..407241f8c 100644 --- a/test/Discord.Net.Tests/Tests.Channels.cs +++ b/test/Discord.Net.Tests/Tests.Channels.cs @@ -156,18 +156,6 @@ namespace Discord 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 @@ namespace Discord // 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 }