From f3cd96d2fec0819a60c551fce5f0f8bd4f3a11da Mon Sep 17 00:00:00 2001 From: james7132 Date: Tue, 25 Oct 2016 21:37:18 +0000 Subject: [PATCH 1/6] Implemented IComparable on IRole and IGuildUUser --- src/Discord.Net.Core/Entities/Roles/IRole.cs | 4 ++-- src/Discord.Net.Core/Entities/Users/IGuildUser.cs | 2 +- .../Extensions/GuildUserExtensions.cs | 12 ++++++++++++ src/Discord.Net.Rest/Entities/Roles/RestRole.cs | 6 +++--- src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs | 3 +++ .../Entities/Roles/SocketRole.cs | 1 + .../Entities/Users/SocketGuildUser.cs | 1 + 7 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Roles/IRole.cs b/src/Discord.Net.Core/Entities/Roles/IRole.cs index aa34fb019..2e3d63702 100644 --- a/src/Discord.Net.Core/Entities/Roles/IRole.cs +++ b/src/Discord.Net.Core/Entities/Roles/IRole.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; namespace Discord { - public interface IRole : ISnowflakeEntity, IDeletable, IMentionable + public interface IRole : ISnowflakeEntity, IDeletable, IMentionable, IComparable { /// Gets the guild owning this role. IGuild Guild { get; } @@ -27,4 +27,4 @@ namespace Discord ///// Modifies this role. Task ModifyAsync(Action func, RequestOptions options = null); } -} \ No newline at end of file +} diff --git a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs index b48c76a37..139640e5a 100644 --- a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs +++ b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace Discord { /// A Guild-User pairing. - public interface IGuildUser : IUser, IVoiceState + public interface IGuildUser : IUser, IVoiceState, IComparable { /// Gets when this user joined this guild. DateTimeOffset? JoinedAt { get; } diff --git a/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs b/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs index 57d6a13dc..51e00fb42 100644 --- a/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs +++ b/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs @@ -15,5 +15,17 @@ namespace Discord => RemoveRolesAsync(user, (IEnumerable)roles); public static Task RemoveRolesAsync(this IGuildUser user, IEnumerable roles) => user.ModifyAsync(x => x.RoleIds = user.RoleIds.Except(roles.Select(y => y.Id)).ToArray()); + + public static IEnumerable GetRoles(this IGuildUser user) { + var guild = user.Guild; + return user.RoleIds.Select(r => guild.GetRole(r)); + } + + internal static int Compare(this IGuildUser u1, IGuildUser u2) { + var r1 = u1.GetRoles().Max(); + var r2 = u2.GetRoles().Max(); + var result = r1.CompareTo(r2); + return result != 0 ? result : u1.Id.CompareTo(u2.Id); + } } } diff --git a/src/Discord.Net.Rest/Entities/Roles/RestRole.cs b/src/Discord.Net.Rest/Entities/Roles/RestRole.cs index 6e81ce9df..60d868caa 100644 --- a/src/Discord.Net.Rest/Entities/Roles/RestRole.cs +++ b/src/Discord.Net.Rest/Entities/Roles/RestRole.cs @@ -4,9 +4,7 @@ using System.Diagnostics; using System.Threading.Tasks; using Model = Discord.API.Role; -namespace Discord.Rest -{ - [DebuggerDisplay(@"{DebuggerDisplay,nq}")] +namespace Discord.Rest { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestRole : RestEntity, IRole { public RestGuild Guild { get; } @@ -51,10 +49,12 @@ namespace Discord.Rest public Task DeleteAsync(RequestOptions options = null) => RoleHelper.DeleteAsync(this, Discord, options); + public override string ToString() => Name; private string DebuggerDisplay => $"{Name} ({Id})"; //IRole IGuild IRole.Guild => Guild; + public int CompareTo(IRole role) => Position.CompareTo(role.Position); } } diff --git a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs index 180ad38bc..6e242e264 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs @@ -96,6 +96,8 @@ namespace Discord.Rest throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); } } + + public int CompareTo(IGuildUser user) => this.Compare(user); //IVoiceState bool IVoiceState.IsSelfDeafened => false; @@ -103,5 +105,6 @@ namespace Discord.Rest bool IVoiceState.IsSuppressed => false; IVoiceChannel IVoiceState.VoiceChannel => null; string IVoiceState.VoiceSessionId => null; + } } diff --git a/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs b/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs index 515389da1..d6612dcb6 100644 --- a/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs +++ b/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs @@ -57,5 +57,6 @@ namespace Discord.WebSocket //IRole IGuild IRole.Guild => Guild; + public int CompareTo(IRole role) => Position.CompareTo(role.Position); } } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs index 5a670c14d..3610b6284 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs @@ -96,6 +96,7 @@ namespace Discord.WebSocket IGuild IGuildUser.Guild => Guild; ulong IGuildUser.GuildId => Guild.Id; IReadOnlyCollection IGuildUser.RoleIds => RoleIds; + public int CompareTo(IGuildUser user) => this.Compare(user); //IUser Task IUser.GetDMChannelAsync(CacheMode mode, RequestOptions options) From 50d1aa068956f709ae190a036be44f8e8ffd4742 Mon Sep 17 00:00:00 2001 From: james7132 Date: Tue, 25 Oct 2016 21:43:41 +0000 Subject: [PATCH 2/6] Implemented IComparable on IGuildUser --- src/Discord.Net.Core/Entities/Users/IGuildUser.cs | 2 +- src/Discord.Net.Core/Extensions/GuildUserExtensions.cs | 5 +++++ src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs | 1 + src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs index 139640e5a..01ce78a24 100644 --- a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs +++ b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace Discord { /// A Guild-User pairing. - public interface IGuildUser : IUser, IVoiceState, IComparable + public interface IGuildUser : IUser, IVoiceState, IComparable, IComparable { /// Gets when this user joined this guild. DateTimeOffset? JoinedAt { get; } diff --git a/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs b/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs index 51e00fb42..b66a75b1f 100644 --- a/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs +++ b/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs @@ -22,10 +22,15 @@ namespace Discord } internal static int Compare(this IGuildUser u1, IGuildUser u2) { + // These should never be empty since the everyone role is always present var r1 = u1.GetRoles().Max(); var r2 = u2.GetRoles().Max(); var result = r1.CompareTo(r2); return result != 0 ? result : u1.Id.CompareTo(u2.Id); } + + internal static int Compare(this IGuildUser user, IRole role) { + return user.GetRoles().Max().CompareTo(role); + } } } diff --git a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs index 6e242e264..bebd245e6 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs @@ -98,6 +98,7 @@ namespace Discord.Rest } public int CompareTo(IGuildUser user) => this.Compare(user); + public int CompareTo(IRole role) => this.Compare(role); //IVoiceState bool IVoiceState.IsSelfDeafened => false; diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs index 3610b6284..9c8165d30 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs @@ -97,6 +97,7 @@ namespace Discord.WebSocket ulong IGuildUser.GuildId => Guild.Id; IReadOnlyCollection IGuildUser.RoleIds => RoleIds; public int CompareTo(IGuildUser user) => this.Compare(user); + public int CompareTo(IRole role) => this.Compare(role); //IUser Task IUser.GetDMChannelAsync(CacheMode mode, RequestOptions options) From 08c7b49aae27098c84b361542748f49ac2b0962e Mon Sep 17 00:00:00 2001 From: james7132 Date: Sat, 29 Oct 2016 07:50:26 +0000 Subject: [PATCH 3/6] Remove IComparable --- src/Discord.Net.Core/Entities/Users/IGuildUser.cs | 2 +- src/Discord.Net.Core/Extensions/GuildUserExtensions.cs | 4 ++-- src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs | 1 - src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs index 01ce78a24..3808bd435 100644 --- a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs +++ b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace Discord { /// A Guild-User pairing. - public interface IGuildUser : IUser, IVoiceState, IComparable, IComparable + public interface IGuildUser : IUser, IVoiceState, IComparable { /// Gets when this user joined this guild. DateTimeOffset? JoinedAt { get; } diff --git a/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs b/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs index b66a75b1f..4067d0b3e 100644 --- a/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs +++ b/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs @@ -21,7 +21,7 @@ namespace Discord return user.RoleIds.Select(r => guild.GetRole(r)); } - internal static int Compare(this IGuildUser u1, IGuildUser u2) { + public static int CompareRoles(this IGuildUser u1, IGuildUser u2) { // These should never be empty since the everyone role is always present var r1 = u1.GetRoles().Max(); var r2 = u2.GetRoles().Max(); @@ -29,7 +29,7 @@ namespace Discord return result != 0 ? result : u1.Id.CompareTo(u2.Id); } - internal static int Compare(this IGuildUser user, IRole role) { + public static int Compare(this IGuildUser user, IRole role) { return user.GetRoles().Max().CompareTo(role); } } diff --git a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs index bebd245e6..154307ace 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs @@ -97,7 +97,6 @@ namespace Discord.Rest } } - public int CompareTo(IGuildUser user) => this.Compare(user); public int CompareTo(IRole role) => this.Compare(role); //IVoiceState diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs index 9c8165d30..05ca7aabc 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs @@ -96,7 +96,6 @@ namespace Discord.WebSocket IGuild IGuildUser.Guild => Guild; ulong IGuildUser.GuildId => Guild.Id; IReadOnlyCollection IGuildUser.RoleIds => RoleIds; - public int CompareTo(IGuildUser user) => this.Compare(user); public int CompareTo(IRole role) => this.Compare(role); //IUser From 2e9bca5b85f8547844f21548cb4b348ced8181df Mon Sep 17 00:00:00 2001 From: james7132 Date: Sat, 29 Oct 2016 08:03:58 +0000 Subject: [PATCH 4/6] Fix role comparison --- .../Extensions/RoleExtensions.cs | 19 +++++++++++++++++++ .../Entities/Roles/RestRole.cs | 2 +- .../Entities/Roles/SocketRole.cs | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 src/Discord.Net.Core/Extensions/RoleExtensions.cs diff --git a/src/Discord.Net.Core/Extensions/RoleExtensions.cs b/src/Discord.Net.Core/Extensions/RoleExtensions.cs new file mode 100644 index 000000000..db146a36c --- /dev/null +++ b/src/Discord.Net.Core/Extensions/RoleExtensions.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Discord +{ + public static class RoleExtensions + { + internal static int Compare(this IRole r1, IRole r2) { + if(r2 == null) + return 1; + var result = r1.Position.CompareTo(r2.Position); + // As per Discord's documentation, a tie is broken by ID + if(result != 0) + return result; + return r1.Id.CompareTo(r2.Id); + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Roles/RestRole.cs b/src/Discord.Net.Rest/Entities/Roles/RestRole.cs index 60d868caa..bfa081def 100644 --- a/src/Discord.Net.Rest/Entities/Roles/RestRole.cs +++ b/src/Discord.Net.Rest/Entities/Roles/RestRole.cs @@ -55,6 +55,6 @@ namespace Discord.Rest { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] //IRole IGuild IRole.Guild => Guild; - public int CompareTo(IRole role) => Position.CompareTo(role.Position); + public int CompareTo(IRole role) => this.Compare(role); } } diff --git a/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs b/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs index d6612dcb6..5fa585138 100644 --- a/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs +++ b/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs @@ -57,6 +57,6 @@ namespace Discord.WebSocket //IRole IGuild IRole.Guild => Guild; - public int CompareTo(IRole role) => Position.CompareTo(role.Position); + public int CompareTo(IRole role) => this.CompareTo(role); } } From 89e61fe7d7b0c3447c8ba87429c7f377756bc67a Mon Sep 17 00:00:00 2001 From: james7132 Date: Sat, 29 Oct 2016 20:36:56 +0000 Subject: [PATCH 5/6] Fixed variable naming --- src/Discord.Net.Core/Extensions/GuildUserExtensions.cs | 9 ++++----- src/Discord.Net.Core/Extensions/RoleExtensions.cs | 10 ++++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs b/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs index 4067d0b3e..ee53fceb8 100644 --- a/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs +++ b/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs @@ -21,12 +21,11 @@ namespace Discord return user.RoleIds.Select(r => guild.GetRole(r)); } - public static int CompareRoles(this IGuildUser u1, IGuildUser u2) { + public static int CompareRoles(this IGuildUser left, IGuildUser right) { // These should never be empty since the everyone role is always present - var r1 = u1.GetRoles().Max(); - var r2 = u2.GetRoles().Max(); - var result = r1.CompareTo(r2); - return result != 0 ? result : u1.Id.CompareTo(u2.Id); + var roleLeft = left.GetRoles().Max(); + var roleRight= right.GetRoles().Max(); + return roleLeft.CompareTo(roleRight); } public static int Compare(this IGuildUser user, IRole role) { diff --git a/src/Discord.Net.Core/Extensions/RoleExtensions.cs b/src/Discord.Net.Core/Extensions/RoleExtensions.cs index db146a36c..ae2d1ccce 100644 --- a/src/Discord.Net.Core/Extensions/RoleExtensions.cs +++ b/src/Discord.Net.Core/Extensions/RoleExtensions.cs @@ -6,14 +6,16 @@ namespace Discord { public static class RoleExtensions { - internal static int Compare(this IRole r1, IRole r2) { - if(r2 == null) + internal static int Compare(this IRole left, IRole right) { + if(left == null) + return -1; + if(right == null) return 1; - var result = r1.Position.CompareTo(r2.Position); + var result = left.Position.CompareTo(right.Position); // As per Discord's documentation, a tie is broken by ID if(result != 0) return result; - return r1.Id.CompareTo(r2.Id); + return left.Id.CompareTo(right.Id); } } } From 97a6bf6b6edb7eefe14040fba159f8d68b3bc5c8 Mon Sep 17 00:00:00 2001 From: james7132 Date: Sat, 29 Oct 2016 23:05:56 +0000 Subject: [PATCH 6/6] Add IGuildUser.Hirearchy, added docstrings Property can be renamed as needed. --- .../Entities/Users/IGuildUser.cs | 5 +++++ .../Extensions/GuildUserExtensions.cs | 19 ++++++++++++------- .../Entities/Users/RestGuildUser.cs | 4 ++-- .../Entities/Users/SocketGuildUser.cs | 3 ++- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs index 3808bd435..d944104a2 100644 --- a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs +++ b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs @@ -28,5 +28,10 @@ namespace Discord Task KickAsync(RequestOptions options = null); /// Modifies this user's properties in this guild. Task ModifyAsync(Action func, RequestOptions options = null); + + /// The position of the user within the role hirearchy. + /// The returned value equal to the position of the highest role the user has, + /// or int.MaxValue if user is the server owner. + int Hirearchy { get; } } } diff --git a/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs b/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs index ee53fceb8..181442150 100644 --- a/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs +++ b/src/Discord.Net.Core/Extensions/GuildUserExtensions.cs @@ -21,15 +21,20 @@ namespace Discord return user.RoleIds.Select(r => guild.GetRole(r)); } - public static int CompareRoles(this IGuildUser left, IGuildUser right) { - // These should never be empty since the everyone role is always present - var roleLeft = left.GetRoles().Max(); - var roleRight= right.GetRoles().Max(); - return roleLeft.CompareTo(roleRight); + internal static int GetHirearchy(this IGuildUser user) { + if(user == null) + return -1; + if(user.Id == user.Guild.OwnerId) + return int.MaxValue; + return user.GetRoles().Max(r => r.Position); } - public static int Compare(this IGuildUser user, IRole role) { - return user.GetRoles().Max().CompareTo(role); + internal static int CompareRole(this IGuildUser user, IRole role) { + if(user == null) + return -1; + if(role == null) + return 1; + return -user.Hirearchy.CompareTo(role.Position); } } } diff --git a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs index 154307ace..227699bbd 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs @@ -96,8 +96,8 @@ namespace Discord.Rest throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); } } - - public int CompareTo(IRole role) => this.Compare(role); + public int Hirearchy => this.GetHirearchy(); + public int CompareTo(IRole role) => this.CompareRole(role); //IVoiceState bool IVoiceState.IsSelfDeafened => false; diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs index 05ca7aabc..b04a0471b 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs @@ -96,7 +96,8 @@ namespace Discord.WebSocket IGuild IGuildUser.Guild => Guild; ulong IGuildUser.GuildId => Guild.Id; IReadOnlyCollection IGuildUser.RoleIds => RoleIds; - public int CompareTo(IRole role) => this.Compare(role); + public int CompareTo(IRole role) => this.CompareRole(role); + public int Hirearchy => this.GetHirearchy(); //IUser Task IUser.GetDMChannelAsync(CacheMode mode, RequestOptions options)