From 8eff92844645bf8606574ab1682411f1e47babc7 Mon Sep 17 00:00:00 2001 From: Velvet <42438262+VelvetThePanda@users.noreply.github.com> Date: Sun, 11 Dec 2022 02:38:12 -0500 Subject: [PATCH 1/2] Support for avatar decorations --- .../API/Objects/Users/IPartialUser.cs | 3 + .../API/Objects/Users/IUser.cs | 8 +++ Backend/Remora.Discord.API/API/CDN.cs | 69 +++++++++++++++++++ .../API/Gateway/Events/Users/UserUpdate.cs | 1 + .../API/Objects/Users/PartialUser.cs | 1 + .../API/Objects/Users/User.cs | 1 + .../API/Objects/Users/UserMention.cs | 2 + 7 files changed, 85 insertions(+) diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Users/IPartialUser.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Users/IPartialUser.cs index 81871241fd..9e9b2f5c7e 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Users/IPartialUser.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Users/IPartialUser.cs @@ -44,6 +44,9 @@ public interface IPartialUser /// Optional Avatar { get; } + /// + Optional AvatarDecoration { get; } + /// Optional IsBot { get; } diff --git a/Backend/Remora.Discord.API.Abstractions/API/Objects/Users/IUser.cs b/Backend/Remora.Discord.API.Abstractions/API/Objects/Users/IUser.cs index ed75ee73a7..76e490c8ed 100644 --- a/Backend/Remora.Discord.API.Abstractions/API/Objects/Users/IUser.cs +++ b/Backend/Remora.Discord.API.Abstractions/API/Objects/Users/IUser.cs @@ -52,6 +52,11 @@ public interface IUser : IPartialUser /// new IImageHash? Avatar { get; } + /// + /// Gets the user's avatar decoration. + /// + new Optional AvatarDecoration { get; } + /// /// Gets a value indicating whether the user is a bot, belonging to an OAuth2 application. /// @@ -120,6 +125,9 @@ public interface IUser : IPartialUser /// Optional IPartialUser.Avatar => new(this.Avatar); + /// + Optional IPartialUser.AvatarDecoration => this.AvatarDecoration; + /// Optional IPartialUser.IsBot => this.IsBot; diff --git a/Backend/Remora.Discord.API/API/CDN.cs b/Backend/Remora.Discord.API/API/CDN.cs index e22385cac2..59f06d0e5b 100644 --- a/Backend/Remora.Discord.API/API/CDN.cs +++ b/Backend/Remora.Discord.API/API/CDN.cs @@ -409,6 +409,75 @@ public static Result GetGuildBannerUrl return ub.Uri; } + /// + /// Gets the CDN URI of the given user's avatar decoration. + /// + /// The user. + /// The requested image format. + /// The requested image size. May be any power of two between 16 and 4096. + /// A result which may or may not have succeeded. + public static Result GetUserAvatarDecorationUrl + ( + IUser user, + Optional imageFormat = default, + Optional imageSize = default + ) + { + return user.AvatarDecoration.IsDefined(out var decoration) + ? GetUserAvatarDecorationUrl(user.ID, decoration, imageFormat, imageSize) + : new ImageNotFoundError(); + } + + /// + /// Gets the CDN URI of the given user's avatar decoration. + /// + /// The ID of the user. + /// The image hash of the user's avatar decoration. + /// The requested image format. + /// The requested image size. May be any power of two between 16 and 4096. + /// A result which may or may not have succeeded. + public static Result GetUserAvatarDecorationUrl + ( + Snowflake userID, + IImageHash avatarDecorationHash, + Optional imageFormat = default, + Optional imageSize = default + ) + { + var formatValidation = ValidateOrDefaultImageFormat + ( + imageFormat, + CDNImageFormat.PNG, + CDNImageFormat.JPEG, + CDNImageFormat.WebP + ); + + if (!formatValidation.IsSuccess) + { + return Result.FromError(formatValidation); + } + + var format = formatValidation.Entity; + + var checkImageSize = CheckImageSize(imageSize); + if (!checkImageSize.IsSuccess) + { + return Result.FromError(checkImageSize); + } + + var ub = new UriBuilder(Constants.CDNBaseURL) + { + Path = $"avatar-decorations/{userID}/{avatarDecorationHash.Value}.{format.ToFileExtension()}" + }; + + if (imageSize.HasValue) + { + ub.Query = $"size={imageSize.Value}"; + } + + return ub.Uri; + } + /// /// Gets the CDN URI of the given user's banner. /// diff --git a/Backend/Remora.Discord.API/API/Gateway/Events/Users/UserUpdate.cs b/Backend/Remora.Discord.API/API/Gateway/Events/Users/UserUpdate.cs index 02ae48edfe..291cdbc14a 100644 --- a/Backend/Remora.Discord.API/API/Gateway/Events/Users/UserUpdate.cs +++ b/Backend/Remora.Discord.API/API/Gateway/Events/Users/UserUpdate.cs @@ -36,6 +36,7 @@ public record UserUpdate string Username, ushort Discriminator, IImageHash? Avatar, + Optional AvatarDecoration = default, Optional IsBot = default, Optional IsSystem = default, Optional IsMFAEnabled = default, diff --git a/Backend/Remora.Discord.API/API/Objects/Users/PartialUser.cs b/Backend/Remora.Discord.API/API/Objects/Users/PartialUser.cs index cf19542db6..0387f7d461 100644 --- a/Backend/Remora.Discord.API/API/Objects/Users/PartialUser.cs +++ b/Backend/Remora.Discord.API/API/Objects/Users/PartialUser.cs @@ -37,6 +37,7 @@ public record PartialUser Optional Username = default, Optional Discriminator = default, Optional Avatar = default, + Optional AvatarDecoration = default, Optional IsBot = default, Optional IsSystem = default, Optional IsMFAEnabled = default, diff --git a/Backend/Remora.Discord.API/API/Objects/Users/User.cs b/Backend/Remora.Discord.API/API/Objects/Users/User.cs index d5440700ea..0e5630d11d 100644 --- a/Backend/Remora.Discord.API/API/Objects/Users/User.cs +++ b/Backend/Remora.Discord.API/API/Objects/Users/User.cs @@ -37,6 +37,7 @@ public record User string Username, ushort Discriminator, IImageHash? Avatar, + Optional AvatarDecoration = default, Optional IsBot = default, Optional IsSystem = default, Optional IsMFAEnabled = default, diff --git a/Backend/Remora.Discord.API/API/Objects/Users/UserMention.cs b/Backend/Remora.Discord.API/API/Objects/Users/UserMention.cs index ad7774ff6c..80ea9ebaf2 100644 --- a/Backend/Remora.Discord.API/API/Objects/Users/UserMention.cs +++ b/Backend/Remora.Discord.API/API/Objects/Users/UserMention.cs @@ -35,6 +35,7 @@ public record UserMention string Username, ushort Discriminator, IImageHash? Avatar, + Optional AvatarDecoration = default, Optional IsBot = default, Optional IsSystem = default, Optional IsMFAEnabled = default, @@ -53,6 +54,7 @@ public record UserMention Username, Discriminator, Avatar, + AvatarDecoration, IsBot, IsSystem, IsMFAEnabled, From 8a726a66f4dcf06d2a9b017453ff5c246b9d9c7f Mon Sep 17 00:00:00 2001 From: Velvet <42438262+VelvetThePanda@users.noreply.github.com> Date: Sun, 11 Dec 2022 10:03:45 -0500 Subject: [PATCH 2/2] Add `avatar_decoration` to requisite payload JSON --- Tests/Remora.Discord.Tests/Samples/Objects/USER/USER.json | 1 + .../Samples/Objects/USER_MENTION/USER_MENTION.json | 1 + 2 files changed, 2 insertions(+) diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/USER/USER.json b/Tests/Remora.Discord.Tests/Samples/Objects/USER/USER.json index 88dc232b74..f67cc0322f 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/USER/USER.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/USER/USER.json @@ -3,6 +3,7 @@ "username": "none", "discriminator": "9999", "avatar": "68b329da9893e34099c7d8ad5cb9c940", + "avatar_decoration": "68b329da9893e34099c7d8ad5cb9c940", "bot": false, "system": false, "mfa_enabled": false, diff --git a/Tests/Remora.Discord.Tests/Samples/Objects/USER_MENTION/USER_MENTION.json b/Tests/Remora.Discord.Tests/Samples/Objects/USER_MENTION/USER_MENTION.json index bf212d578b..5dc21ddaa0 100644 --- a/Tests/Remora.Discord.Tests/Samples/Objects/USER_MENTION/USER_MENTION.json +++ b/Tests/Remora.Discord.Tests/Samples/Objects/USER_MENTION/USER_MENTION.json @@ -3,6 +3,7 @@ "username": "none", "discriminator": "9999", "avatar": "68b329da9893e34099c7d8ad5cb9c940", + "avatar_decoration": "68b329da9893e34099c7d8ad5cb9c940", "bot": false, "system": false, "mfa_enabled": false,