diff --git a/src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs b/src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs index 81bf42d8e..2e9272729 100644 --- a/src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/IGuildChannel.cs @@ -10,6 +10,8 @@ namespace Discord /// Gets the position of this channel in the guild's channel list, relative to others of the same type. int Position { get; } + /// Gets the guild this channel is a member of. + IGuild Guild { get; } /// Gets the id of the guild this channel is a member of. ulong GuildId { get; } /// Gets a collection of permission overwrites for this channel. diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuildIntegration.cs b/src/Discord.Net.Core/Entities/Guilds/IGuildIntegration.cs index 1a0c6d2d0..225ce05d6 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IGuildIntegration.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IGuildIntegration.cs @@ -14,6 +14,7 @@ namespace Discord DateTimeOffset SyncedAt { get; } IntegrationAccount Account { get; } + IGuild Guild { get; } ulong GuildId { get; } ulong RoleId { get; } IUser User { get; } diff --git a/src/Discord.Net.Core/Entities/Invites/IInvite.cs b/src/Discord.Net.Core/Entities/Invites/IInvite.cs index 081b57d76..a023749c2 100644 --- a/src/Discord.Net.Core/Entities/Invites/IInvite.cs +++ b/src/Discord.Net.Core/Entities/Invites/IInvite.cs @@ -9,8 +9,12 @@ namespace Discord /// Gets the url used to accept this invite, using Code. string Url { get; } - /// Gets the id of the the channel this invite is linked to. + /// Gets the channel this invite is linked to. + IChannel Channel { get; } + /// Gets the id of the channel this invite is linked to. ulong ChannelId { get; } + /// Gets the guild this invite is linked to. + IGuild Guild { get; } /// Gets the id of the guild this invite is linked to. ulong GuildId { get; } diff --git a/src/Discord.Net.Core/Entities/Messages/IMessage.cs b/src/Discord.Net.Core/Entities/Messages/IMessage.cs index 9b15d1b07..2eff88495 100644 --- a/src/Discord.Net.Core/Entities/Messages/IMessage.cs +++ b/src/Discord.Net.Core/Entities/Messages/IMessage.cs @@ -20,7 +20,7 @@ namespace Discord /// Gets the time of this message's last edit, if any. DateTimeOffset? EditedTimestamp { get; } - /// Gets the id of the channel this message was sent to. + /// Gets the channel this message was sent to. IMessageChannel Channel { get; } /// Gets the author of this message. IUser Author { get; } diff --git a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs index 7763a14ae..b48c76a37 100644 --- a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs +++ b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs @@ -14,6 +14,8 @@ namespace Discord string Nickname { get; } GuildPermissions GuildPermissions { get; } + /// Gets the guild for this user. + IGuild Guild { get; } /// Gets the id of the guild for this user. ulong GuildId { get; } /// Returns a collection of the ids of the roles this user is a member of in this guild, including the guild's @everyone role. diff --git a/src/Discord.Net.Rest/ClientHelper.cs b/src/Discord.Net.Rest/ClientHelper.cs index f1c619e02..e7ef55033 100644 --- a/src/Discord.Net.Rest/ClientHelper.cs +++ b/src/Discord.Net.Rest/ClientHelper.cs @@ -41,7 +41,7 @@ namespace Discord.Rest { var model = await client.ApiClient.GetInviteAsync(inviteId).ConfigureAwait(false); if (model != null) - return RestInvite.Create(client, model); + return RestInvite.Create(client, null, null, model); return null; } diff --git a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs index 697203223..c41ba5da6 100644 --- a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs +++ b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs @@ -47,7 +47,7 @@ namespace Discord.Rest RequestOptions options) { var models = await client.ApiClient.GetChannelInvitesAsync(channel.Id, options).ConfigureAwait(false); - return models.Select(x => RestInviteMetadata.Create(client, x)).ToImmutableArray(); + return models.Select(x => RestInviteMetadata.Create(client, null, channel, x)).ToImmutableArray(); } public static async Task CreateInviteAsync(IChannel channel, BaseDiscordClient client, int? maxAge, int? maxUses, bool isTemporary, RequestOptions options) @@ -58,7 +58,7 @@ namespace Discord.Rest if (maxUses.HasValue) args.MaxUses = maxUses.Value; var model = await client.ApiClient.CreateChannelInviteAsync(channel.Id, args, options).ConfigureAwait(false); - return RestInviteMetadata.Create(client, model); + return RestInviteMetadata.Create(client, null, channel, model); } //Messages diff --git a/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs index 2607a2d96..0e6e55772 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs @@ -125,6 +125,16 @@ namespace Discord.Rest public override string ToString() => Name; //IGuildChannel + IGuild IGuildChannel.Guild + { + get + { + if (Guild != null) + return Guild; + throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); + } + } + async Task> IGuildChannel.GetInvitesAsync(RequestOptions options) => await GetInvitesAsync(options).ConfigureAwait(false); async Task IGuildChannel.CreateInviteAsync(int? maxAge, int? maxUses, bool isTemporary, RequestOptions options) diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs index a27475e3c..664e75ec8 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs @@ -117,14 +117,14 @@ namespace Discord.Rest RequestOptions options) { var models = await client.ApiClient.GetGuildIntegrationsAsync(guild.Id, options).ConfigureAwait(false); - return models.Select(x => RestGuildIntegration.Create(client, x)).ToImmutableArray(); + return models.Select(x => RestGuildIntegration.Create(client, guild, x)).ToImmutableArray(); } public static async Task CreateIntegrationAsync(IGuild guild, BaseDiscordClient client, ulong id, string type, RequestOptions options) { var args = new CreateGuildIntegrationParams(id, type); var model = await client.ApiClient.CreateGuildIntegrationAsync(guild.Id, args, options).ConfigureAwait(false); - return RestGuildIntegration.Create(client, model); + return RestGuildIntegration.Create(client, guild, model); } //Invites @@ -132,7 +132,7 @@ namespace Discord.Rest RequestOptions options) { var models = await client.ApiClient.GetGuildInvitesAsync(guild.Id, options).ConfigureAwait(false); - return models.Select(x => RestInviteMetadata.Create(client, x)).ToImmutableArray(); + return models.Select(x => RestInviteMetadata.Create(client, guild, null, x)).ToImmutableArray(); } //Roles diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuildIntegration.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuildIntegration.cs index b90c492ab..fc2bfd8b2 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuildIntegration.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuildIntegration.cs @@ -21,16 +21,18 @@ namespace Discord.Rest public ulong RoleId { get; private set; } public RestUser User { get; private set; } public IntegrationAccount Account { get; private set; } + internal IGuild Guild { get; private set; } public DateTimeOffset SyncedAt => DateTimeUtils.FromTicks(_syncedAtTicks); - internal RestGuildIntegration(BaseDiscordClient discord, ulong id) + internal RestGuildIntegration(BaseDiscordClient discord, IGuild guild, ulong id) : base(discord, id) { + Guild = guild; } - internal static RestGuildIntegration Create(BaseDiscordClient discord, Model model) + internal static RestGuildIntegration Create(BaseDiscordClient discord, IGuild guild, Model model) { - var entity = new RestGuildIntegration(discord, model.Id); + var entity = new RestGuildIntegration(discord, guild, model.Id); entity.Update(model); return entity; } @@ -71,6 +73,15 @@ namespace Discord.Rest public override string ToString() => Name; private string DebuggerDisplay => $"{Name} ({Id}{(IsEnabled ? ", Enabled" : "")})"; + IGuild IGuildIntegration.Guild + { + get + { + if (Guild != null) + return Guild; + throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); + } + } IUser IGuildIntegration.User => User; } } diff --git a/src/Discord.Net.Rest/Entities/Invites/RestInvite.cs b/src/Discord.Net.Rest/Entities/Invites/RestInvite.cs index 4c870f3f4..4a6b5bae4 100644 --- a/src/Discord.Net.Rest/Entities/Invites/RestInvite.cs +++ b/src/Discord.Net.Rest/Entities/Invites/RestInvite.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.Threading.Tasks; using Model = Discord.API.Invite; @@ -11,17 +12,21 @@ namespace Discord.Rest public string GuildName { get; private set; } public ulong ChannelId { get; private set; } public ulong GuildId { get; private set; } + internal IChannel Channel { get; private set; } + internal IGuild Guild { get; private set; } public string Code => Id; public string Url => $"{DiscordConfig.InviteUrl}/{Code}"; - internal RestInvite(BaseDiscordClient discord, string id) + internal RestInvite(BaseDiscordClient discord, IGuild guild, IChannel channel, string id) : base(discord, id) { + Guild = guild; + Channel = channel; } - internal static RestInvite Create(BaseDiscordClient discord, Model model) + internal static RestInvite Create(BaseDiscordClient discord, IGuild guild, IChannel channel, Model model) { - var entity = new RestInvite(discord, model.Code); + var entity = new RestInvite(discord, guild, channel, model.Code); entity.Update(model); return entity; } @@ -46,7 +51,27 @@ namespace Discord.Rest public override string ToString() => Url; private string DebuggerDisplay => $"{Url} ({GuildName} / {ChannelName})"; - - string IEntity.Id => Code; + + IGuild IInvite.Guild + { + get + { + if (Guild != null) + return Guild; + var guildChannel = Channel as IGuildChannel; + if (guildChannel != null) + return guildChannel.Guild; //If it fails, it'll still return this exception + throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); + } + } + IChannel IInvite.Channel + { + get + { + if (Channel != null) + return Channel; + throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); + } + } } } diff --git a/src/Discord.Net.Rest/Entities/Invites/RestInviteMetadata.cs b/src/Discord.Net.Rest/Entities/Invites/RestInviteMetadata.cs index cd1a66311..9298b42e9 100644 --- a/src/Discord.Net.Rest/Entities/Invites/RestInviteMetadata.cs +++ b/src/Discord.Net.Rest/Entities/Invites/RestInviteMetadata.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using Model = Discord.API.InviteMetadata; namespace Discord.Rest @@ -17,13 +16,13 @@ namespace Discord.Rest public DateTimeOffset CreatedAt => DateTimeUtils.FromTicks(_createdAtTicks); - internal RestInviteMetadata(BaseDiscordClient discord, string id) - : base(discord, id) + internal RestInviteMetadata(BaseDiscordClient discord, IGuild guild, IChannel channel, string id) + : base(discord, guild, channel, id) { } - internal static RestInviteMetadata Create(BaseDiscordClient discord, Model model) + internal static RestInviteMetadata Create(BaseDiscordClient discord, IGuild guild, IChannel channel, Model model) { - var entity = new RestInviteMetadata(discord, model.Code); + var entity = new RestInviteMetadata(discord, guild, channel, model.Code); entity.Update(model); return entity; } diff --git a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs index 6d1cac024..180ad38bc 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs @@ -86,6 +86,17 @@ namespace Discord.Rest return new ChannelPermissions(Permissions.ResolveChannel(Guild, this, channel, guildPerms.RawValue)); } + //IGuildUser + IGuild IGuildUser.Guild + { + get + { + if (Guild != null) + return Guild; + throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); + } + } + //IVoiceState bool IVoiceState.IsSelfDeafened => false; bool IVoiceState.IsSelfMuted => false; diff --git a/src/Discord.Net.Rpc/Entities/Channels/RpcGuildChannel.cs b/src/Discord.Net.Rpc/Entities/Channels/RpcGuildChannel.cs index 9b010b903..8a0ac2a9e 100644 --- a/src/Discord.Net.Rpc/Entities/Channels/RpcGuildChannel.cs +++ b/src/Discord.Net.Rpc/Entities/Channels/RpcGuildChannel.cs @@ -58,6 +58,15 @@ namespace Discord.Rpc public override string ToString() => Name; //IGuildChannel + IGuild IGuildChannel.Guild + { + get + { + //Always fails + throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); + } + } + async Task> IGuildChannel.GetInvitesAsync(RequestOptions options) => await GetInvitesAsync(options).ConfigureAwait(false); async Task IGuildChannel.CreateInviteAsync(int? maxAge, int? maxUses, bool isTemporary, RequestOptions options) diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs index 4253b3c51..45d58b42c 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs @@ -126,6 +126,7 @@ namespace Discord.WebSocket internal override SocketUser GetUserInternal(ulong id) => GetUser(id); //IGuildChannel + IGuild IGuildChannel.Guild => Guild; ulong IGuildChannel.GuildId => Guild.Id; async Task> IGuildChannel.GetInvitesAsync(RequestOptions options) diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs index 00972f51a..5a670c14d 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs @@ -93,6 +93,7 @@ namespace Discord.WebSocket internal new SocketGuildUser Clone() => MemberwiseClone() as SocketGuildUser; //IGuildUser + IGuild IGuildUser.Guild => Guild; ulong IGuildUser.GuildId => Guild.Id; IReadOnlyCollection IGuildUser.RoleIds => RoleIds;