diff --git a/DisCatSharp/Entities/User/DiscordUser.cs b/DisCatSharp/Entities/User/DiscordUser.cs
index 97d758645..1affd4727 100644
--- a/DisCatSharp/Entities/User/DiscordUser.cs
+++ b/DisCatSharp/Entities/User/DiscordUser.cs
@@ -1,718 +1,727 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using DisCatSharp.Attributes;
using DisCatSharp.Entities.OAuth2;
using DisCatSharp.Enums;
using DisCatSharp.Exceptions;
using DisCatSharp.Net;
using DisCatSharp.Net.Abstractions;
using Newtonsoft.Json;
namespace DisCatSharp.Entities;
///
/// Represents a Discord user.
///
public class DiscordUser : SnowflakeObject, IEquatable
{
///
/// Initializes a new instance of the class.
///
internal DiscordUser()
: base(["display_name", "linked_users", "banner_color"])
{ }
///
/// Initializes a new instance of the class.
///
/// The transport user.
internal DiscordUser(TransportUser transport)
{
this.Id = transport.Id;
this.Username = transport.Username;
this.Discriminator = transport.Discriminator;
this.AvatarHash = transport.AvatarHash;
this.AvatarDecorationData = transport.AvatarDecorationData;
this.BannerHash = transport.BannerHash;
this.BannerColorInternal = transport.BannerColor;
this.ThemeColorsInternal = [.. transport.ThemeColors ?? []];
this.IsBot = transport.IsBot;
this.MfaEnabled = transport.MfaEnabled;
this.Verified = transport.Verified;
this.Email = transport.Email;
this.PremiumType = transport.PremiumType;
this.Locale = transport.Locale;
this.Flags = transport.Flags;
this.OAuthFlags = transport.OAuthFlags;
this.Bio = transport.Bio;
this.Pronouns = transport.Pronouns;
this.GlobalName = transport.GlobalName;
}
///
/// Gets this user's username.
///
[JsonProperty("username", NullValueHandling = NullValueHandling.Ignore)]
public virtual string Username { get; internal set; }
///
/// Gets this user's username with the discriminator.
/// Example: Discord#0000
///
[JsonIgnore, DiscordDeprecated("We will internally use the GlobalName if a user is already migrated. This will be removed in future. Consider switching to UsernameWithGlobalName then.")]
public virtual string UsernameWithDiscriminator
=> this.IsMigrated ? this.UsernameWithGlobalName : $"{this.Username}#{this.Discriminator}";
///
/// Gets the username with the global name.
/// Example: @lulalaby (Lala Sabathil)
///
[JsonIgnore, DiscordInExperiment]
public virtual string UsernameWithGlobalName
=> this.GlobalName != null ? $"{this.Username} ({this.GlobalName})" : this.Username;
///
/// Gets this user's global name.
/// Only applicable if is .
///
[JsonProperty("global_name", NullValueHandling = NullValueHandling.Ignore), DiscordInExperiment]
public virtual string? GlobalName { get; internal set; }
///
/// Whether this user account is migrated to the new username system.
/// Learn more at dis.gd/usernames.
///
[JsonIgnore]
public virtual bool IsMigrated
=> this.Discriminator == "0";
///
/// Gets the user's 4-digit discriminator.
///
[JsonProperty("discriminator", NullValueHandling = NullValueHandling.Ignore), DiscordDeprecated("Users are being migrated currently. Bots still have discrims")]
public virtual string Discriminator { get; internal set; }
///
/// Gets the discriminator integer.
///
[JsonIgnore, Deprecated("Users are being migrated currently. Bots still have discrims")]
internal int DiscriminatorInt
=> int.Parse(this.Discriminator, NumberStyles.Integer, CultureInfo.InvariantCulture);
///
/// Gets the user's banner color, if set. Mutually exclusive with .
///
[JsonIgnore]
public virtual DiscordColor? BannerColor
=> !this.BannerColorInternal.HasValue ? null : new DiscordColor(this.BannerColorInternal.Value);
///
/// Gets the user's theme colors, if set.
///
[JsonIgnore]
public virtual IReadOnlyList? ThemeColors => !(this.ThemeColorsInternal is not null && this.ThemeColorsInternal.Count != 0) ? null : this.ThemeColorsInternal.Select(x => new DiscordColor(x)).ToList();
///
/// Gets the user's banner color integer.
///
[JsonProperty("accent_color")]
internal int? BannerColorInternal;
///
/// Gets the user's theme color integers.
///
[JsonProperty("theme_colors", NullValueHandling = NullValueHandling.Ignore)]
internal List? ThemeColorsInternal;
///
/// Gets the user's banner url
///
[JsonIgnore]
public string? BannerUrl
=> string.IsNullOrWhiteSpace(this.BannerHash) ? null : $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.BANNERS}/{this.Id.ToString(CultureInfo.InvariantCulture)}/{this.BannerHash}.{(this.BannerHash.StartsWith("a_", StringComparison.Ordinal) ? "gif" : "png")}?size=4096";
///
/// Gets the user's profile banner hash. Mutually exclusive with .
///
[JsonProperty("banner", NullValueHandling = NullValueHandling.Ignore)]
public virtual string BannerHash { get; internal set; }
///
/// Gets the users bio.
/// This is not available to bots tho.
///
[JsonProperty("bio", NullValueHandling = NullValueHandling.Ignore)]
public virtual string Bio { get; internal set; }
///
/// Gets the user's avatar hash.
///
[JsonProperty("avatar", NullValueHandling = NullValueHandling.Ignore)]
public virtual string AvatarHash { get; internal set; }
///
/// Gets the user's avatar decoration data.
///
[JsonProperty("avatar_decoration_data", NullValueHandling = NullValueHandling.Ignore)]
public virtual AvatarDecorationData AvatarDecorationData { get; internal set; }
///
/// Returns a uri to this users profile.
///
[JsonIgnore]
public Uri ProfileUri
=> new($"{DiscordDomain.GetDomain(CoreDomain.Discord).Url}{Endpoints.USERS}/{this.Id}");
///
/// Returns a string representing the direct URL to this users profile.
///
/// The URL of this users profile.
[JsonIgnore]
public string ProfileUrl
=> this.ProfileUri.AbsoluteUri;
///
/// Gets the user's avatar url.
///
[JsonIgnore]
public string AvatarUrl
=> string.IsNullOrWhiteSpace(this.AvatarHash) ? this.DefaultAvatarUrl : $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.AVATARS}/{this.Id.ToString(CultureInfo.InvariantCulture)}/{this.AvatarHash}.{(this.AvatarHash.StartsWith("a_", StringComparison.Ordinal) ? "gif" : "png")}?size=1024";
///
/// Gets the user's avatar decoration url.
///
[JsonIgnore]
public string? AvatarDecorationUrl => this.AvatarDecorationData?.AssetUrl;
///
/// Gets the URL of default avatar for this user.
///
[JsonIgnore]
public string DefaultAvatarUrl
=> $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.EMBED}{Endpoints.AVATARS}/{(this.IsMigrated ? (this.Id >> 22) % 6 : Convert.ToUInt64(this.DiscriminatorInt) % 5).ToString(CultureInfo.InvariantCulture)}.png?size=1024";
///
/// Gets whether the user is a bot.
///
[JsonProperty("bot", NullValueHandling = NullValueHandling.Ignore)]
public virtual bool IsBot { get; internal set; }
///
/// Gets whether the user has multi-factor authentication enabled.
///
[JsonProperty("mfa_enabled", NullValueHandling = NullValueHandling.Ignore)]
public virtual bool? MfaEnabled { get; internal set; }
///
/// Gets whether the user is an official Discord system user.
///
[JsonProperty("system", NullValueHandling = NullValueHandling.Ignore)]
public virtual bool? IsSystem { get; internal set; }
///
/// Gets whether the user is verified.
/// This is only present in OAuth.
///
[JsonProperty("verified", NullValueHandling = NullValueHandling.Ignore)]
public virtual bool? Verified { get; internal set; }
///
/// Gets the user's email address.
/// This is only present in OAuth.
///
[JsonProperty("email", NullValueHandling = NullValueHandling.Ignore)]
public virtual string? Email { get; internal set; }
///
/// Gets the user's premium type.
///
[JsonProperty("premium_type", NullValueHandling = NullValueHandling.Ignore)]
public virtual PremiumType? PremiumType { get; internal set; }
///
/// Gets the user's chosen language
///
[JsonProperty("locale", NullValueHandling = NullValueHandling.Ignore)]
public virtual string Locale { get; internal set; }
///
/// Gets the user's flags for OAuth.
///
[JsonProperty("flags", NullValueHandling = NullValueHandling.Ignore)]
public virtual UserFlags? OAuthFlags { get; internal set; }
///
/// Gets the user's flags.
///
[JsonProperty("public_flags", NullValueHandling = NullValueHandling.Ignore)]
public virtual UserFlags? Flags { get; internal set; }
///
/// Gets the user's pronouns.
///
[JsonProperty("pronouns", NullValueHandling = NullValueHandling.Ignore)]
public virtual string? Pronouns { get; internal set; }
///
/// Gets the user's mention string.
///
[JsonIgnore]
public string Mention
=> this.Mention(this is DiscordMember);
///
/// Gets whether this user is the Client which created this object.
///
[JsonIgnore]
public bool IsCurrent
=> this.Id == this.Discord.CurrentUser.Id;
///
/// Gets the user's access token.
/// Can be used in combination with .
/// You can generate a token object from json with , if needed.
/// As alternative you can construct the object via new DiscordAccessToken(string accessToken, string tokenType, int expiresIn, string refreshToken, string scope)
.
///
[JsonIgnore]
- public DiscordAccessToken AccessToken { get; set; }
+ public DiscordAccessToken? AccessToken { get; set; }
#region Extension of DiscordUser
///
/// Whether this member is a
///
///
[JsonIgnore]
public bool IsMod
=> this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.CertifiedModerator);
///
/// Whether this member is a
///
///
[JsonIgnore]
public bool IsPartner
=> this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.Partner);
///
/// Whether this member is a
///
///
[JsonIgnore]
public bool IsVerifiedBot
=> this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.VerifiedBot);
///
/// Whether this member is a
///
///
[JsonIgnore]
public bool IsBotDev
=> this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.VerifiedDeveloper);
///
/// Whether this member is a
///
///
[JsonIgnore]
public bool IsActiveDeveloper
=> this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.ActiveDeveloper);
///
/// Whether this member is a
///
///
[JsonIgnore]
public bool IsStaff
=> this.Flags.HasValue && this.Flags.Value.HasFlag(UserFlags.Staff);
#endregion
#region OAuth2 Methods
///
/// Gets the current user's connections.
/// Requires a set in .
///
/// The oauth2 client.
+ /// Thrown when is not present.
public async Task> OAuth2GetConnectionsAsync(DiscordOAuth2Client oauth2Client)
- => await oauth2Client.GetCurrentUserConnectionsAsync(this.AccessToken);
+ => this.AccessToken is not null ? await oauth2Client.GetCurrentUserConnectionsAsync(this.AccessToken) : throw new NullReferenceException("You need to specify the AccessToken on this DiscordUser entity.");
///
/// Gets the current user's guilds.
/// Requires a set in .
///
/// The oauth2 client.
+ /// Thrown when is not present.
public async Task> OAuth2GetGuildAsync(DiscordOAuth2Client oauth2Client)
- => await oauth2Client.GetCurrentUserGuildsAsync(this.AccessToken);
+ => this.AccessToken is not null ? await oauth2Client.GetCurrentUserGuildsAsync(this.AccessToken) : throw new NullReferenceException("You need to specify the AccessToken on this DiscordUser entity.");
///
/// Gets the current user's member object for given .
/// Requires a set in .
///
/// The oauth2 client.
/// The guild to get the member object for.
+ /// Thrown when is not present.
public async Task OAuth2GetGuildMemberAsync(DiscordOAuth2Client oauth2Client, DiscordGuild guild)
- => await oauth2Client.GetCurrentUserGuildMemberAsync(this.AccessToken, guild.Id);
+ => this.AccessToken is not null ? await oauth2Client.GetCurrentUserGuildMemberAsync(this.AccessToken, guild.Id) : throw new NullReferenceException("You need to specify the AccessToken on this DiscordUser entity.");
///
/// Gets the current user's member object for given .
/// Requires a set in .
///
/// The oauth2 client.
/// The guild id to get the member object for.
+ /// Thrown when is not present.
public async Task OAuth2GetGuildMemberAsync(DiscordOAuth2Client oauth2Client, ulong guildId)
- => await oauth2Client.GetCurrentUserGuildMemberAsync(this.AccessToken, guildId);
+ => this.AccessToken is not null ? await oauth2Client.GetCurrentUserGuildMemberAsync(this.AccessToken, guildId) : throw new NullReferenceException("You need to specify the AccessToken on this DiscordUser entity.");
///
/// Adds the user to the given .
/// Some parameters might need additional permissions for the bot on the target guild. See https://discord.com/developers/docs/resources/guild#add-guild-member for details.
///
/// The oauth2 client.
/// The guild id to add the member to.
/// The new nickname.
/// The new roles.
/// Whether this user has to be muted.
/// Whether this user has to be deafened.
+ /// Thrown when is not present.
public async Task OAuth2AddToGuildAsync(DiscordOAuth2Client oauth2Client, ulong guildId, string? nickname = null, IEnumerable? roles = null, bool? muted = null, bool? deafened = null)
- => await oauth2Client.AddCurrentUserToGuildAsync(this.AccessToken, this.Id, guildId, nickname, roles, muted, deafened);
+ => this.AccessToken is not null ? await oauth2Client.AddCurrentUserToGuildAsync(this.AccessToken, this.Id, guildId, nickname, roles, muted, deafened) : throw new NullReferenceException("You need to specify the AccessToken on this DiscordUser entity.");
///
/// Adds the user to the given .
/// Some parameters might need additional permissions for the bot on the target guild. See https://discord.com/developers/docs/resources/guild#add-guild-member for details.
///
/// The oauth2 client.
/// The guild to add the member to.
/// The new nickname.
/// The new roles.
/// Whether this user has to be muted.
/// Whether this user has to be deafened.
+ /// Thrown when is not present.
public async Task OAuth2AddToGuildAsync(DiscordOAuth2Client oauth2Client, DiscordGuild guild, string? nickname = null, IEnumerable? roles = null, bool? muted = null, bool? deafened = null)
- => await oauth2Client.AddCurrentUserToGuildAsync(this.AccessToken, this.Id, guild.Id, nickname, roles, muted, deafened);
+ => this.AccessToken is not null ? await oauth2Client.AddCurrentUserToGuildAsync(this.AccessToken, this.Id, guild.Id, nickname, roles, muted, deafened) : throw new NullReferenceException("You need to specify the AccessToken on this DiscordUser entity.");
///
/// Gets the current user's oauth2 object.
/// Requires a set in .
///
/// The oauth2 client.
+ /// Thrown when is not present.
public async Task OAuth2GetAsync(DiscordOAuth2Client oauth2Client)
- => await oauth2Client.GetCurrentUserAsync(this.AccessToken);
+ => this.AccessToken is not null ? await oauth2Client.GetCurrentUserAsync(this.AccessToken) : throw new NullReferenceException("You need to specify the AccessToken on this DiscordUser entity.");
///
/// Gets the current user's authorization info.
/// Requires a set in .
///
/// The oauth2 client.
+ /// Thrown when is not present.
public async Task OAuth2GetAuthorizationInfoAsync(DiscordOAuth2Client oauth2Client)
- => await oauth2Client.GetCurrentAuthorizationInformationAsync(this.AccessToken);
+ => this.AccessToken is not null ? await oauth2Client.GetCurrentAuthorizationInformationAsync(this.AccessToken) : throw new NullReferenceException("You need to specify the AccessToken on this DiscordUser entity.");
///
/// Gets the current user's application role connection.
/// Requires a set in .
///
/// The oauth2 client.
+ /// Thrown when is not present.
public async Task OAuth2GetApplicationRoleConnectionAsync(DiscordOAuth2Client oauth2Client)
- => await oauth2Client.GetCurrentUserApplicationRoleConnectionAsync(this.AccessToken);
+ => this.AccessToken is not null ? await oauth2Client.GetCurrentUserApplicationRoleConnectionAsync(this.AccessToken) : throw new NullReferenceException("You need to specify the AccessToken on this DiscordUser entity.");
#endregion
///
/// Fetches the user from the API.
///
/// The user with fresh data from the API.
public async Task GetFromApiAsync()
=> await this.Discord.ApiClient.GetUserAsync(this.Id).ConfigureAwait(false);
///
/// Gets additional information about an application if the user is an bot.
///
/// The rpc info or
/// Thrown when the application does not exist.
/// Thrown when an invalid parameter was provided.
/// Thrown when Discord is unable to process the request.
public async Task GetRpcInfoAsync()
=> this.IsBot ? await this.Discord.ApiClient.GetApplicationRpcInfoAsync(this.Id).ConfigureAwait(false) : await Task.FromResult(null).ConfigureAwait(false);
///
/// Whether this user is in a
///
///
///
/// DiscordGuild guild = await Client.GetGuildAsync(806675511555915806);
/// DiscordUser user = await Client.GetUserAsync(469957180968271873);
/// Console.WriteLine($"{user.Username} {(user.IsInGuild(guild) ? "is a" : "is not a")} member of {guild.Name}");
///
/// results to J_M_Lutra is a member of Project Nyaw~.
///
///
///
public async Task IsInGuild(DiscordGuild guild)
{
try
{
var member = await guild.GetMemberAsync(this.Id).ConfigureAwait(false);
return member is not null;
}
catch (NotFoundException)
{
return false;
}
}
///
/// Whether this user is not in a
///
///
///
public async Task IsNotInGuild(DiscordGuild guild)
=> !await this.IsInGuild(guild).ConfigureAwait(false);
///
/// Returns the DiscordMember in the specified
///
/// The to get this user on.
/// The .
/// Thrown when the user is not part of the guild.
/// Thrown when an invalid parameter was provided.
/// Thrown when Discord is unable to process the request.
public async Task ConvertToMember(DiscordGuild guild)
=> await guild.GetMemberAsync(this.Id).ConfigureAwait(false);
///
/// Unbans this user from a guild.
///
/// Guild to unban this user from.
/// Reason for audit logs.
/// Thrown when the client does not have the permission.
/// Thrown when the user does not exist.
/// Thrown when an invalid parameter was provided.
/// Thrown when Discord is unable to process the request.
public Task UnbanAsync(DiscordGuild guild, string? reason = null)
=> guild.UnbanMemberAsync(this, reason);
///
/// Gets this user's presence.
///
[JsonIgnore]
public DiscordPresence? Presence
=> this.Discord is DiscordClient dc && dc.Presences.TryGetValue(this.Id, out var presence) ? presence : null;
///
/// Gets the user's avatar URL, in requested format and size.
///
/// Format of the avatar to get.
/// Maximum size of the avatar. Must be a power of two, minimum 16, maximum 2048.
/// URL of the user's avatar.
public string GetAvatarUrl(ImageFormat fmt, ushort size = 1024)
{
if (fmt is ImageFormat.Unknown)
throw new ArgumentException("You must specify valid image format.", nameof(fmt));
if (size is < 16 or > 2048)
throw new ArgumentOutOfRangeException(nameof(size));
var log = Math.Log(size, 2);
if (log < 4 || log > 11 || log % 1 is not 0)
throw new ArgumentOutOfRangeException(nameof(size));
var sfmt = fmt switch
{
ImageFormat.Gif => "gif",
ImageFormat.Jpeg => "jpg",
ImageFormat.Png => "png",
ImageFormat.WebP => "webp",
ImageFormat.Auto => !string.IsNullOrWhiteSpace(this.AvatarHash) ? this.AvatarHash.StartsWith("a_", StringComparison.Ordinal) ? "gif" : "png" : "png",
_ => throw new ArgumentOutOfRangeException(nameof(fmt))
};
var ssize = size.ToString(CultureInfo.InvariantCulture);
if (!string.IsNullOrWhiteSpace(this.AvatarHash))
{
var id = this.Id.ToString(CultureInfo.InvariantCulture);
return $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.AVATARS}/{id}/{this.AvatarHash}.{sfmt}?size={ssize}";
}
var type = (this.DiscriminatorInt % 5).ToString(CultureInfo.InvariantCulture);
return $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.EMBED}{Endpoints.AVATARS}/{type}.{sfmt}?size={ssize}";
}
///
/// Creates a direct message channel to this user.
///
/// Direct message channel to this user.
/// Thrown when the user has the bot blocked, the member shares no guild with the bot, or if the member has Allow DM from server members off.
/// Thrown when the user does not exist.
/// Thrown when an invalid parameter was provided.
/// Thrown when Discord is unable to process the request.
public Task CreateDmChannelAsync()
=> this.Discord.ApiClient.CreateDmAsync(this.Id);
///
/// Sends a direct message to this user. Creates a direct message channel if one does not exist already.
///
/// Content of the message to send.
/// The sent message.
/// Thrown when the user has the bot blocked, the member shares no guild with the bot, or if the member has Allow DM from server members off.
/// Thrown when the user does not exist.
/// Thrown when an invalid parameter was provided.
/// Thrown when Discord is unable to process the request.
public async Task SendMessageAsync(string content)
{
if (this.IsBot && this.Discord.CurrentUser.IsBot)
throw new ArgumentException("Bots cannot DM each other.");
var chn = await this.CreateDmChannelAsync().ConfigureAwait(false);
return await chn.SendMessageAsync(content).ConfigureAwait(false);
}
///
/// Sends a direct message to this user. Creates a direct message channel if one does not exist already.
///
/// Embed to attach to the message.
/// The sent message.
/// Thrown when the user has the bot blocked, the member shares no guild with the bot, or if the member has Allow DM from server members off.
/// Thrown when the user does not exist.
/// Thrown when an invalid parameter was provided.
/// Thrown when Discord is unable to process the request.
public async Task SendMessageAsync(DiscordEmbed embed)
{
if (this.IsBot && this.Discord.CurrentUser.IsBot)
throw new ArgumentException("Bots cannot DM each other.");
var chn = await this.CreateDmChannelAsync().ConfigureAwait(false);
return await chn.SendMessageAsync(embed).ConfigureAwait(false);
}
///
/// Sends a direct message to this user. Creates a direct message channel if one does not exist already.
///
/// Content of the message to send.
/// Embed to attach to the message.
/// The sent message.
/// Thrown when the user has the bot blocked, the member shares no guild with the bot, or if the member has Allow DM from server members off.
/// Thrown when the user does not exist.
/// Thrown when an invalid parameter was provided.
/// Thrown when Discord is unable to process the request.
public async Task SendMessageAsync(string content, DiscordEmbed embed)
{
if (this.IsBot && this.Discord.CurrentUser.IsBot)
throw new ArgumentException("Bots cannot DM each other.");
var chn = await this.CreateDmChannelAsync().ConfigureAwait(false);
return await chn.SendMessageAsync(content, embed).ConfigureAwait(false);
}
///
/// Sends a direct message to this user. Creates a direct message channel if one does not exist already.
///
/// Builder to with the message.
/// The sent message.
/// Thrown when the user has the bot blocked, the member shares no guild with the bot, or if the member has Allow DM from server members off.
/// Thrown when the user does not exist.
/// Thrown when an invalid parameter was provided.
/// Thrown when Discord is unable to process the request.
public async Task SendMessageAsync(DiscordMessageBuilder message)
{
if (this.IsBot && this.Discord.CurrentUser.IsBot)
throw new ArgumentException("Bots cannot DM each other.");
var chn = await this.CreateDmChannelAsync().ConfigureAwait(false);
return await chn.SendMessageAsync(message).ConfigureAwait(false);
}
///
/// Returns a string representation of this user.
///
/// String representation of this user.
public override string ToString()
=> this.IsMigrated ? $"User {this.Id}; {this.UsernameWithGlobalName}" : $"User {this.Id}; {this.UsernameWithDiscriminator}";
///
/// Checks whether this is equal to another object.
///
/// Object to compare to.
/// Whether the object is equal to this .
public override bool Equals(object obj)
=> this.Equals(obj as DiscordUser);
///
/// Checks whether this is equal to another .
///
/// to compare to.
/// Whether the is equal to this .
public bool Equals(DiscordUser e)
=> e is not null && (ReferenceEquals(this, e) || this.Id == e.Id);
///
/// Gets the hash code for this .
///
/// The hash code for this .
public override int GetHashCode()
=> this.Id.GetHashCode();
///
/// Gets whether the two objects are equal.
///
/// First user to compare.
/// Second user to compare.
/// Whether the two users are equal.
public static bool operator ==(DiscordUser? e1, DiscordUser? e2)
{
var o1 = e1 as object;
var o2 = e2 as object;
return (o1 is null && o2 is null) || (o1 is not null && o2 is not null && e1.Id == e2.Id);
}
///
/// Gets whether the two objects are not equal.
///
/// First user to compare.
/// Second user to compare.
/// Whether the two users are not equal.
public static bool operator !=(DiscordUser? e1, DiscordUser? e2)
=> !(e1 == e2);
}
///
/// Represents a user's avatar decoration data.
///
public class AvatarDecorationData
{
[JsonProperty("asset", NullValueHandling = NullValueHandling.Ignore)]
public string Asset { get; internal set; }
///
/// Gets the user's avatar decoration url.
///
[JsonIgnore]
public string? AssetUrl => string.IsNullOrWhiteSpace(this.Asset) ? null : $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.AVATARS_DECORATION_PRESETS}/{this.Asset}.png?size=1024";
[JsonProperty("sku_id", NullValueHandling = NullValueHandling.Ignore)]
public ulong SkuId { get; internal set; }
}
///
/// Represents a user comparer.
///
internal sealed class DiscordUserComparer : IEqualityComparer
{
///
/// Whether the users are equal.
///
/// The first user
/// The second user.
public bool Equals(DiscordUser x, DiscordUser y)
=> x.Equals(y);
///
/// Gets the hash code.
///
/// The user.
public int GetHashCode(DiscordUser obj)
=> obj.Id.GetHashCode();
}