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,