diff --git a/src/Discord.Net.Core/CDN.cs b/src/Discord.Net.Core/CDN.cs index e1e8e5e1a..b1879eebc 100644 --- a/src/Discord.Net.Core/CDN.cs +++ b/src/Discord.Net.Core/CDN.cs @@ -46,6 +46,24 @@ namespace Discord string extension = FormatToExtension(format, avatarId); return $"{DiscordConfig.CDNUrl}avatars/{userId}/{avatarId}.{extension}?size={size}"; } + + /// + /// Returns a user banner URL. + /// + /// The user snowflake identifier. + /// The banner identifier. + /// The size of the image to return in horizontal pixels. This can be any power of two between 16 and 2048. + /// The format to return. + /// + /// A URL pointing to the user's banner in the specified size. + /// + public static string GetUserBannerUrl(ulong userId, string bannerId, ushort size, ImageFormat format) + { + if (bannerId == null) + return null; + string extension = FormatToExtension(format, bannerId); + return $"{DiscordConfig.CDNUrl}banners/{userId}/{bannerId}.{extension}?size={size}"; + } /// /// Returns the default user avatar URL. /// diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml index 0510de74a..b41bdd2f8 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.xml +++ b/src/Discord.Net.Core/Discord.Net.Core.xml @@ -10144,6 +10144,11 @@ Gets the user that created this webhook. + + + Gets the ID of the application owning this webhook. + + Modifies this webhook. diff --git a/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs b/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs index bb2f80a81..4027db408 100644 --- a/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs +++ b/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs @@ -10,11 +10,6 @@ namespace Discord /// public class ComponentBuilder { - /// - /// The max length of a . - /// - public const int MaxLabelLength = 80; - /// /// The max length of a . /// @@ -307,17 +302,22 @@ namespace Discord /// public class ButtonBuilder { + /// + /// The max length of a . + /// + public const int MaxLabelLength = 80; + /// /// Gets or sets the label of the current button. /// - /// length exceeds . + /// length exceeds . public string Label { get => _label; set { - if (value != null && value.Length > ComponentBuilder.MaxLabelLength) - throw new ArgumentException(message: $"Button label must be {ComponentBuilder.MaxLabelLength} characters or less!", paramName: nameof(Label)); + if (value != null && value.Length > MaxLabelLength) + throw new ArgumentException(message: $"Button label must be {MaxLabelLength} characters or less!", paramName: nameof(Label)); _label = value; } @@ -539,8 +539,8 @@ namespace Discord if (string.IsNullOrEmpty(this.Url)) throw new InvalidOperationException("Link buttons must have a link associated with them"); else - UrlValidation.Validate(this.Url); - } + UrlValidation.Validate(this.Url); + } else if (string.IsNullOrEmpty(this.CustomId)) throw new InvalidOperationException("Non-link buttons must have a custom id associated with them"); @@ -831,23 +831,28 @@ namespace Discord /// public class SelectMenuOptionBuilder { + /// + /// The maximum length of a . + /// + public const int MaxLabelLength = 100; + /// /// The maximum length of a . /// - public const int MaxDescriptionLength = 50; + public const int MaxDescriptionLength = 100; /// /// Gets or sets the label of the current select menu. /// - /// length exceeds + /// length exceeds public string Label { get => _label; set { if (value != null) - if (value.Length > ComponentBuilder.MaxLabelLength) - throw new ArgumentException(message: $"Button label must be {ComponentBuilder.MaxLabelLength} characters or less!", paramName: nameof(Label)); + if (value.Length > MaxLabelLength) + throw new ArgumentException(message: $"Button label must be {MaxLabelLength} characters or less!", paramName: nameof(Label)); _label = value; } diff --git a/src/Discord.Net.Core/Entities/Roles/Color.cs b/src/Discord.Net.Core/Entities/Roles/Color.cs index 7c2d152a4..ee50710e8 100644 --- a/src/Discord.Net.Core/Entities/Roles/Color.cs +++ b/src/Discord.Net.Core/Entities/Roles/Color.cs @@ -10,68 +10,70 @@ namespace Discord [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public struct Color { + /// Gets the max decimal value of color. + public const uint MaxDecimalValue = 0xFFFFFF; /// Gets the default user color value. - public static readonly Color Default = new Color(0); + public static readonly Color Default = new(0); /// Gets the teal color value. /// A color struct with the hex value of 1ABC9C. - public static readonly Color Teal = new Color(0x1ABC9C); + public static readonly Color Teal = new(0x1ABC9C); /// Gets the dark teal color value. /// A color struct with the hex value of 11806A. - public static readonly Color DarkTeal = new Color(0x11806A); + public static readonly Color DarkTeal = new(0x11806A); /// Gets the green color value. /// A color struct with the hex value of 2ECC71. - public static readonly Color Green = new Color(0x2ECC71); + public static readonly Color Green = new(0x2ECC71); /// Gets the dark green color value. /// A color struct with the hex value of 1F8B4C. - public static readonly Color DarkGreen = new Color(0x1F8B4C); + public static readonly Color DarkGreen = new(0x1F8B4C); /// Gets the blue color value. /// A color struct with the hex value of 3498DB. - public static readonly Color Blue = new Color(0x3498DB); + public static readonly Color Blue = new(0x3498DB); /// Gets the dark blue color value. /// A color struct with the hex value of 206694. - public static readonly Color DarkBlue = new Color(0x206694); + public static readonly Color DarkBlue = new(0x206694); /// Gets the purple color value. /// A color struct with the hex value of 9B59B6. - public static readonly Color Purple = new Color(0x9B59B6); + public static readonly Color Purple = new(0x9B59B6); /// Gets the dark purple color value. /// A color struct with the hex value of 71368A. - public static readonly Color DarkPurple = new Color(0x71368A); + public static readonly Color DarkPurple = new(0x71368A); /// Gets the magenta color value. /// A color struct with the hex value of E91E63. - public static readonly Color Magenta = new Color(0xE91E63); + public static readonly Color Magenta = new(0xE91E63); /// Gets the dark magenta color value. /// A color struct with the hex value of AD1457. - public static readonly Color DarkMagenta = new Color(0xAD1457); + public static readonly Color DarkMagenta = new(0xAD1457); /// Gets the gold color value. /// A color struct with the hex value of F1C40F. - public static readonly Color Gold = new Color(0xF1C40F); + public static readonly Color Gold = new(0xF1C40F); /// Gets the light orange color value. /// A color struct with the hex value of C27C0E. - public static readonly Color LightOrange = new Color(0xC27C0E); + public static readonly Color LightOrange = new(0xC27C0E); /// Gets the orange color value. /// A color struct with the hex value of E67E22. - public static readonly Color Orange = new Color(0xE67E22); + public static readonly Color Orange = new(0xE67E22); /// Gets the dark orange color value. /// A color struct with the hex value of A84300. - public static readonly Color DarkOrange = new Color(0xA84300); + public static readonly Color DarkOrange = new(0xA84300); /// Gets the red color value. /// A color struct with the hex value of E74C3C. - public static readonly Color Red = new Color(0xE74C3C); + public static readonly Color Red = new(0xE74C3C); /// Gets the dark red color value. /// A color struct with the hex value of 992D22. - public static readonly Color DarkRed = new Color(0x992D22); + public static readonly Color DarkRed = new(0x992D22); /// Gets the light grey color value. /// A color struct with the hex value of 979C9F. - public static readonly Color LightGrey = new Color(0x979C9F); + public static readonly Color LightGrey = new(0x979C9F); /// Gets the lighter grey color value. /// A color struct with the hex value of 95A5A6. - public static readonly Color LighterGrey = new Color(0x95A5A6); + public static readonly Color LighterGrey = new(0x95A5A6); /// Gets the dark grey color value. /// A color struct with the hex value of 607D8B. - public static readonly Color DarkGrey = new Color(0x607D8B); + public static readonly Color DarkGrey = new(0x607D8B); /// Gets the darker grey color value. /// A color struct with the hex value of 546E7A. - public static readonly Color DarkerGrey = new Color(0x546E7A); + public static readonly Color DarkerGrey = new(0x546E7A); /// Gets the encoded value for this color. /// @@ -91,22 +93,27 @@ namespace Discord /// Initializes a struct with the given raw value. /// /// - /// The following will create a color that has a hex value of + /// The following will create a color that has a hex value of /// #607D8B. /// /// Color darkGrey = new Color(0x607D8B); /// /// /// The raw value of the color (e.g. 0x607D8B). + /// Value exceeds . public Color(uint rawValue) { + if (rawValue > MaxDecimalValue) + throw new ArgumentException($"{nameof(RawValue)} of color cannot be greater than {MaxDecimalValue}!", nameof(rawValue)); + RawValue = rawValue; } + /// /// Initializes a struct with the given RGB bytes. /// /// - /// The following will create a color that has a value of + /// The following will create a color that has a value of /// #607D8B. /// /// Color darkGrey = new Color((byte)0b_01100000, (byte)0b_01111101, (byte)0b_10001011); @@ -115,19 +122,24 @@ namespace Discord /// The byte that represents the red color. /// The byte that represents the green color. /// The byte that represents the blue color. + /// Value exceeds . public Color(byte r, byte g, byte b) { - RawValue = - ((uint)r << 16) | - ((uint)g << 8) | - (uint)b; + uint value = ((uint)r << 16) + | ((uint)g << 8) + | (uint)b; + + if (value > MaxDecimalValue) + throw new ArgumentException($"{nameof(RawValue)} of color cannot be greater than {MaxDecimalValue}!"); + + RawValue = value; } /// /// Initializes a struct with the given RGB value. /// /// - /// The following will create a color that has a value of + /// The following will create a color that has a value of /// #607D8B. /// /// Color darkGrey = new Color(96, 125, 139); @@ -145,16 +157,15 @@ namespace Discord throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,255]."); if (b < 0 || b > 255) throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,255]."); - RawValue = - ((uint)r << 16) | - ((uint)g << 8) | - (uint)b; + RawValue = ((uint)r << 16) + | ((uint)g << 8) + | (uint)b; } /// /// Initializes a struct with the given RGB float value. /// /// - /// The following will create a color that has a value of + /// The following will create a color that has a value of /// #607c8c. /// /// Color darkGrey = new Color(0.38f, 0.49f, 0.55f); @@ -172,10 +183,9 @@ namespace Discord throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,1]."); if (b < 0.0f || b > 1.0f) throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,1]."); - RawValue = - ((uint)(r * 255.0f) << 16) | - ((uint)(g * 255.0f) << 8) | - (uint)(b * 255.0f); + RawValue = ((uint)(r * 255.0f) << 16) + | ((uint)(g * 255.0f) << 8) + | (uint)(b * 255.0f); } public static bool operator ==(Color lhs, Color rhs) @@ -184,15 +194,22 @@ namespace Discord public static bool operator !=(Color lhs, Color rhs) => lhs.RawValue != rhs.RawValue; + public static implicit operator Color(uint rawValue) + => new(rawValue); + + public static implicit operator uint(Color color) + => color.RawValue; + public override bool Equals(object obj) - => (obj is Color c && RawValue == c.RawValue); + => obj is Color c && RawValue == c.RawValue; public override int GetHashCode() => RawValue.GetHashCode(); - public static implicit operator StandardColor(Color color) => - StandardColor.FromArgb((int)color.RawValue); - public static explicit operator Color(StandardColor color) => - new Color((uint)color.ToArgb() << 8 >> 8); + public static implicit operator StandardColor(Color color) + => StandardColor.FromArgb((int)color.RawValue); + + public static explicit operator Color(StandardColor color) + => new((uint)color.ToArgb() << 8 >> 8); /// /// Gets the hexadecimal representation of the color (e.g. #000ccc). diff --git a/src/Discord.Net.Core/Entities/Users/IUser.cs b/src/Discord.Net.Core/Entities/Users/IUser.cs index 9596a8338..f265bb938 100644 --- a/src/Discord.Net.Core/Entities/Users/IUser.cs +++ b/src/Discord.Net.Core/Entities/Users/IUser.cs @@ -12,17 +12,29 @@ namespace Discord /// string AvatarId { get; } /// + /// Gets the identifier of this user's banner. + /// + string BannerId { get; } + /// + /// Gets the user's banner color. + /// + /// + /// A struct representing the accent color of this user's banner. + /// + Color? AccentColor { get; } + /// /// Gets the avatar URL for this user. /// /// /// This property retrieves a URL for this user's avatar. In event that the user does not have a valid avatar - /// (i.e. their avatar identifier is not set), this property will return null. If you wish to + /// (i.e. their avatar identifier is not set), this method will return null. If you wish to /// retrieve the default avatar for this user, consider using (see /// example). /// /// - /// The following example attempts to retrieve the user's current avatar and send it to a channel; if one is - /// not set, a default avatar for this user will be returned instead. + /// The following example attempts to retrieve the user's current avatar and send it to a channel; if one is + /// not set, a default avatar for this user will be returned instead. /// /// @@ -34,6 +46,16 @@ namespace Discord /// string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128); /// + /// Gets the banner URL for this user. + /// + /// The format to return. + /// The size of the image to return in. This can be any power of two between 16 and 2048. + /// + /// + /// A string representing the user's avatar URL; null if the user does not have an banner in place. + /// + string GetBannerUrl(ImageFormat format = ImageFormat.Auto, ushort size = 256); + /// /// Gets the default avatar URL for this user. /// /// @@ -93,8 +115,8 @@ namespace Discord /// This method is used to obtain or create a channel used to send a direct message. /// /// In event that the current user cannot send a message to the target user, a channel can and will - /// still be created by Discord. However, attempting to send a message will yield a - /// with a 403 as its + /// still be created by Discord. However, attempting to send a message will yield a + /// with a 403 as its /// . There are currently no official workarounds by /// Discord. /// diff --git a/src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs b/src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs index b2d017316..d5bc70d71 100644 --- a/src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs +++ b/src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading.Tasks; namespace Discord @@ -49,6 +49,11 @@ namespace Discord /// IUser Creator { get; } + /// + /// Gets the ID of the application owning this webhook. + /// + ulong? ApplicationId { get; } + /// /// Modifies this webhook. /// diff --git a/src/Discord.Net.Rest/API/Common/User.cs b/src/Discord.Net.Rest/API/Common/User.cs index d1f436afb..4d1b5b2b7 100644 --- a/src/Discord.Net.Rest/API/Common/User.cs +++ b/src/Discord.Net.Rest/API/Common/User.cs @@ -15,6 +15,10 @@ namespace Discord.API public Optional Bot { get; set; } [JsonProperty("avatar")] public Optional Avatar { get; set; } + [JsonProperty("banner")] + public Optional Banner { get; set; } + [JsonProperty("accent_color")] + public Optional AccentColor { get; set; } //CurrentUser [JsonProperty("verified")] diff --git a/src/Discord.Net.Rest/API/Common/Webhook.cs b/src/Discord.Net.Rest/API/Common/Webhook.cs index cbd5fdad5..ff1dca9bd 100644 --- a/src/Discord.Net.Rest/API/Common/Webhook.cs +++ b/src/Discord.Net.Rest/API/Common/Webhook.cs @@ -21,5 +21,7 @@ namespace Discord.API [JsonProperty("user")] public Optional Creator { get; set; } + [JsonProperty("application_id")] + public Optional ApplicationId { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs index ba8fcbb4e..8298ff19c 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs @@ -12,5 +12,7 @@ namespace Discord.API.Rest public Optional Embeds { get; set; } [JsonProperty("allowed_mentions")] public Optional AllowedMentions { get; set; } + [JsonProperty("components")] + public Optional Components { get; set; } } } diff --git a/src/Discord.Net.Rest/Discord.Net.Rest.xml b/src/Discord.Net.Rest/Discord.Net.Rest.xml index 920e0bf60..a594fc985 100644 --- a/src/Discord.Net.Rest/Discord.Net.Rest.xml +++ b/src/Discord.Net.Rest/Discord.Net.Rest.xml @@ -4778,6 +4778,9 @@ + + + diff --git a/src/Discord.Net.Rest/Entities/Users/RestThreadUser.cs b/src/Discord.Net.Rest/Entities/Users/RestThreadUser.cs index d74591e75..bb981bfdb 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestThreadUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestThreadUser.cs @@ -9,7 +9,7 @@ using Model = Discord.API.ThreadMember; namespace Discord.Rest { /// - /// Represents a thread user recieved over the REST api. + /// Represents a thread user received over the REST api. /// public class RestThreadUser : RestEntity { @@ -51,7 +51,7 @@ namespace Discord.Rest /// Gets the guild user for this thread user. /// /// - /// A task representing the asyncronous get operation. The task returns a + /// A task representing the asynchronous get operation. The task returns a /// that represents the current thread user. /// public Task GetGuildUser() diff --git a/src/Discord.Net.Rest/Entities/Users/RestUser.cs b/src/Discord.Net.Rest/Entities/Users/RestUser.cs index 7bc1447fe..618804fef 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestUser.cs @@ -22,6 +22,10 @@ namespace Discord.Rest /// public string AvatarId { get; private set; } /// + public string BannerId { get; private set; } + /// + public Color? AccentColor { get; private set; } + /// public UserProperties? PublicFlags { get; private set; } /// @@ -61,6 +65,10 @@ namespace Discord.Rest { if (model.Avatar.IsSpecified) AvatarId = model.Avatar.Value; + if (model.Banner.IsSpecified) + BannerId = model.Banner.Value; + if (model.AccentColor.IsSpecified) + AccentColor = model.AccentColor.Value; if (model.Discriminator.IsSpecified) DiscriminatorValue = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture); if (model.Bot.IsSpecified) @@ -92,6 +100,10 @@ namespace Discord.Rest public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) => CDN.GetUserAvatarUrl(Id, AvatarId, size, format); + /// + public string GetBannerUrl(ImageFormat format = ImageFormat.Auto, ushort size = 256) + => CDN.GetUserBannerUrl(Id, BannerId, size, format); + /// public string GetDefaultAvatarUrl() => CDN.GetDefaultUserAvatarUrl(DiscriminatorValue); diff --git a/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs b/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs index 9baddf003..0d24f08df 100644 --- a/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs +++ b/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs @@ -24,6 +24,8 @@ namespace Discord.Rest public ulong? GuildId { get; private set; } /// public IUser Creator { get; private set; } + /// + public ulong? ApplicationId { get; private set; } /// public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); @@ -66,6 +68,8 @@ namespace Discord.Rest GuildId = model.GuildId.Value; if (model.Name.IsSpecified) Name = model.Name.Value; + if (model.ApplicationId.IsSpecified) + ApplicationId = model.ApplicationId.Value; } /// diff --git a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs index f8676c783..0c2e0f8c2 100644 --- a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs +++ b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs @@ -68,6 +68,7 @@ namespace Discord.Rest model.Video = entity.Video.Value.ToModel(); return model; } + public static API.AllowedMentions ToModel(this AllowedMentions entity) { return new API.AllowedMentions() diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs index 15c5182fc..b1bce5934 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs @@ -12,6 +12,8 @@ namespace Discord.WebSocket public override string Username { get; internal set; } public override ushort DiscriminatorValue { get; internal set; } public override string AvatarId { get; internal set; } + public override string BannerId { get; internal set; } + public override Color? AccentColor { get; internal set; } internal override SocketPresence Presence { get; set; } public override bool IsWebhook => false; @@ -47,7 +49,7 @@ namespace Discord.WebSocket discord.RemoveUser(Id); } } - + internal void Update(ClientState state, PresenceModel model) { Presence = SocketPresence.Create(model); diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs index 805a88110..d99310540 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs @@ -29,6 +29,10 @@ namespace Discord.WebSocket /// public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } /// + public override string BannerId { get { return GlobalUser.BannerId; } internal set { GlobalUser.BannerId = value; } } + /// + public override Color? AccentColor { get { return GlobalUser.AccentColor; } internal set { GlobalUser.AccentColor = value; } } + /// internal override SocketPresence Presence { get { return GlobalUser.Presence; } set { GlobalUser.Presence = value; } } /// diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs index f79fc7afe..ac8409a32 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs @@ -38,6 +38,11 @@ namespace Discord.WebSocket public override ushort DiscriminatorValue { get { return GlobalUser.DiscriminatorValue; } internal set { GlobalUser.DiscriminatorValue = value; } } /// public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } + /// + public override string BannerId { get { return GlobalUser.BannerId; } internal set { GlobalUser.BannerId = value; } } + /// + public override Color? AccentColor { get { return GlobalUser.AccentColor; } internal set { GlobalUser.AccentColor = value; } } + /// public GuildPermissions GuildPermissions => new GuildPermissions(Permissions.ResolveGuild(Guild, this)); internal override SocketPresence Presence { get; set; } @@ -91,7 +96,7 @@ namespace Discord.WebSocket /// Returns the position of the user within the role hierarchy. /// /// - /// The returned value equal to the position of the highest role the user has, or + /// The returned value equal to the position of the highest role the user has, or /// if user is the server owner. /// public int Hierarchy diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs index 7b11257a3..e821238ee 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs @@ -29,6 +29,10 @@ namespace Discord.WebSocket /// public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } /// + public override string BannerId { get { return GlobalUser.BannerId; } internal set { GlobalUser.BannerId = value; } } + /// + public override Color? AccentColor { get { return GlobalUser.AccentColor; } internal set { GlobalUser.AccentColor = value; } } + /// internal override SocketPresence Presence { get { return GlobalUser.Presence; } set { GlobalUser.Presence = value; } } /// public UserProperties Flags { get; internal set; } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs index d1237d598..5fb1f56e5 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs @@ -36,7 +36,7 @@ namespace Discord.WebSocket /// public string Nickname - => GuildUser.Nickname; + => GuildUser.Nickname; /// public DateTimeOffset? PremiumSince @@ -53,6 +53,20 @@ namespace Discord.WebSocket internal set => GuildUser.AvatarId = value; } + /// + public override string BannerId + { + get => GuildUser.BannerId; + internal set => GuildUser.BannerId = value; + } + + /// + public override Color? AccentColor + { + get => GuildUser.AccentColor; + internal set => GuildUser.AccentColor = value; + } + /// public override ushort DiscriminatorValue { diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs index 840a1c30b..180e60a3b 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs @@ -19,9 +19,16 @@ namespace Discord.WebSocket public override ushort DiscriminatorValue { get; internal set; } /// public override string AvatarId { get; internal set; } + + /// + public override string BannerId { get; internal set; } + + /// + public override Color? AccentColor { get; internal set; } + /// public override bool IsBot { get; internal set; } - + /// public override bool IsWebhook => false; /// diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs index 025daf29a..c50fbee4f 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs @@ -25,6 +25,10 @@ namespace Discord.WebSocket /// public abstract string AvatarId { get; internal set; } /// + public abstract string BannerId { get; internal set; } + /// + public abstract Color? AccentColor { get; internal set; } + /// public abstract bool IsWebhook { get; } /// public UserProperties? PublicFlags { get; private set; } @@ -64,6 +68,16 @@ namespace Discord.WebSocket AvatarId = model.Avatar.Value; hasChanges = true; } + if (model.Banner.IsSpecified && model.Banner.Value != BannerId) + { + BannerId = model.Banner.Value; + hasChanges = true; + } + if (model.AccentColor.IsSpecified && model.AccentColor.Value != AccentColor?.RawValue) + { + AccentColor = model.AccentColor.Value; + hasChanges = true; + } if (model.Discriminator.IsSpecified) { var newVal = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture); @@ -99,6 +113,10 @@ namespace Discord.WebSocket public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) => CDN.GetUserAvatarUrl(Id, AvatarId, size, format); + /// + public string GetBannerUrl(ImageFormat format = ImageFormat.Auto, ushort size = 256) + => CDN.GetUserBannerUrl(Id, BannerId, size, format); + /// public string GetDefaultAvatarUrl() => CDN.GetDefaultUserAvatarUrl(DiscriminatorValue); diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs index 2b0ecbb19..f1269e649 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs @@ -24,6 +24,23 @@ namespace Discord.WebSocket public override ushort DiscriminatorValue { get; internal set; } /// public override string AvatarId { get; internal set; } + + /// + /// Webhook users does not support banners. + public override string BannerId + { + get => throw new NotSupportedException("Webhook users does not support banners."); + internal set => throw new NotSupportedException("Webhook users does not support banners."); + } + + /// + /// Webhook users does not support accent colors. + public override Color? AccentColor + { + get => throw new NotSupportedException("Webhook users does not support accent colors."); + internal set => throw new NotSupportedException("Webhook users does not support accent colors."); + } + /// public override bool IsBot { get; internal set; } diff --git a/src/Discord.Net.Webhook/Discord.Net.Webhook.xml b/src/Discord.Net.Webhook/Discord.Net.Webhook.xml index f629c2c29..d1bafb9a3 100644 --- a/src/Discord.Net.Webhook/Discord.Net.Webhook.xml +++ b/src/Discord.Net.Webhook/Discord.Net.Webhook.xml @@ -31,7 +31,7 @@ Thrown if the is an invalid format. Thrown if the is null or whitespace. - + Sends a message to the channel for this webhook. Returns the ID of the created message. @@ -99,6 +99,11 @@ Gets or sets the allowed mentions of the message. + + + Gets or sets the components that the message should display. + + Could not find a webhook with the supplied credentials. diff --git a/src/Discord.Net.Webhook/DiscordWebhookClient.cs b/src/Discord.Net.Webhook/DiscordWebhookClient.cs index 91d077411..d4affb08b 100644 --- a/src/Discord.Net.Webhook/DiscordWebhookClient.cs +++ b/src/Discord.Net.Webhook/DiscordWebhookClient.cs @@ -88,8 +88,8 @@ namespace Discord.Webhook /// Sends a message to the channel for this webhook. /// Returns the ID of the created message. public Task SendMessageAsync(string text = null, bool isTTS = false, IEnumerable embeds = null, - string username = null, string avatarUrl = null, RequestOptions options = null, AllowedMentions allowedMentions = null) - => WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, allowedMentions, options); + string username = null, string avatarUrl = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent component = null) + => WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, component); /// /// Modifies a message posted using this webhook. diff --git a/src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs b/src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs index dec7b6e3b..ca2ff10a0 100644 --- a/src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs +++ b/src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs @@ -22,5 +22,9 @@ namespace Discord.Webhook /// Gets or sets the allowed mentions of the message. /// public Optional AllowedMentions { get; set; } + /// + /// Gets or sets the components that the message should display. + /// + public Optional Components { get; set; } } } diff --git a/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs b/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs index bbb160fcd..210d8eda0 100644 --- a/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs +++ b/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs @@ -17,6 +17,7 @@ namespace Discord.Webhook public string Name { get; private set; } public string AvatarId { get; private set; } public ulong? GuildId { get; private set; } + public ulong? ApplicationId { get; private set; } public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); @@ -44,6 +45,8 @@ namespace Discord.Webhook GuildId = model.GuildId.Value; if (model.Name.IsSpecified) Name = model.Name.Value; + if (model.ApplicationId.IsSpecified) + ApplicationId = model.ApplicationId.Value; } public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) diff --git a/src/Discord.Net.Webhook/WebhookClientHelper.cs b/src/Discord.Net.Webhook/WebhookClientHelper.cs index 528848f7f..6e3651323 100644 --- a/src/Discord.Net.Webhook/WebhookClientHelper.cs +++ b/src/Discord.Net.Webhook/WebhookClientHelper.cs @@ -21,7 +21,7 @@ namespace Discord.Webhook return RestInternalWebhook.Create(client, model); } public static async Task SendMessageAsync(DiscordWebhookClient client, - string text, bool isTTS, IEnumerable embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options) + string text, bool isTTS, IEnumerable embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options, MessageComponent component) { var args = new CreateWebhookMessageParams { @@ -37,6 +37,8 @@ namespace Discord.Webhook args.AvatarUrl = avatarUrl; if (allowedMentions != null) args.AllowedMentions = allowedMentions.ToModel(); + if (component != null) + args.Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray(); var model = await client.ApiClient.CreateWebhookMessageAsync(client.Webhook.Id, args, options: options).ConfigureAwait(false); return model.Id; @@ -83,7 +85,8 @@ namespace Discord.Webhook : Optional.Create(), AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() - : Optional.Create() + : Optional.Create(), + Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional.Unspecified, }; await client.ApiClient.ModifyWebhookMessageAsync(client.Webhook.Id, messageId, apiArgs, options)