diff --git a/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestEmojiAPI.cs b/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestEmojiAPI.cs
index ba2698960d..04635f5e9d 100644
--- a/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestEmojiAPI.cs
+++ b/Backend/Remora.Discord.API.Abstractions/API/Rest/IDiscordRestEmojiAPI.cs
@@ -37,6 +37,88 @@ namespace Remora.Discord.API.Abstractions.Rest;
[PublicAPI]
public interface IDiscordRestEmojiAPI
{
+ ///
+ /// Gets a list of emojis for the given application.
+ ///
+ /// The ID of the application.
+ /// The cancellation token for this operation.
+ /// A retrieval result which may or may not have succeeded.
+ Task>> ListApplicationEmojisAync
+ (
+ Snowflake applicationID,
+ CancellationToken ct = default
+ );
+
+ ///
+ /// Gets the emoji on the given application with the given ID.
+ ///
+ /// The ID of the application.
+ /// The ID of the emoji.
+ /// The cancellation token for this operation.
+ /// A retrieval result which may or may not have succeeded.
+ Task> GetApplicationEmojiAsync
+ (
+ Snowflake applicationID,
+ Snowflake emojiID,
+ CancellationToken ct = default
+ );
+
+ ///
+ /// Creates a new emoji for the given application with the given parameters.
+ ///
+ ///
+ /// Any streams passed to this method will be disposed of at the end of the call. If you want to reuse the streams
+ /// afterwards, ensure that what you pass is a copy that the method can take ownership of.
+ ///
+ /// The ID of the application.
+ /// The name of the new emoji.
+ /// The image data.
+ /// The reason to mark the action in the audit log with.
+ /// The cancellation token for this operation.
+ /// A creation result which may or may not have succeeded.
+ Task> CreateApplicationEmojiAsync
+ (
+ Snowflake applicationID,
+ string name,
+ Stream image,
+ Optional reason = default,
+ CancellationToken ct = default
+ );
+
+ ///
+ /// Modifies the given emoji.
+ ///
+ /// The ID of the application.
+ /// The ID of the emoji.
+ /// The new name of the emoji.
+ /// The reason to mark the action in the audit log with.
+ /// The cancellation token for this operation.
+ /// A modification result which may or may not have succeeded.
+ Task> ModifyApplicationEmojiAsync
+ (
+ Snowflake applicationID,
+ Snowflake emojiID,
+ Optional name = default,
+ Optional reason = default,
+ CancellationToken ct = default
+ );
+
+ ///
+ /// Deletes the given emoji.
+ ///
+ /// The ID of the application.
+ /// The ID of the emoji.
+ /// The reason to mark the action in the audit log with.
+ /// The cancellation token for this operation.
+ /// A deletion result which may or may not have succeeded.
+ Task DeleteApplicationEmojiAsync
+ (
+ Snowflake applicationID,
+ Snowflake emojiID,
+ Optional reason = default,
+ CancellationToken ct = default
+ );
+
///
/// Gets a list of emojis for the given guild.
///
@@ -56,8 +138,7 @@ Task>> ListGuildEmojisAsync
/// The ID of the emoji.
/// The cancellation token for this operation.
/// A retrieval result which may or may not have succeeded.
- Task> GetGuildEmojiAsync
- (
+ Task> GetGuildEmojiAsync(
Snowflake guildID,
Snowflake emojiID,
CancellationToken ct = default
diff --git a/Backend/Remora.Discord.Rest/API/Emoji/DiscordRestEmojiAPI.cs b/Backend/Remora.Discord.Rest/API/Emoji/DiscordRestEmojiAPI.cs
index 5afc2a4873..424b1abd46 100644
--- a/Backend/Remora.Discord.Rest/API/Emoji/DiscordRestEmojiAPI.cs
+++ b/Backend/Remora.Discord.Rest/API/Emoji/DiscordRestEmojiAPI.cs
@@ -58,6 +58,115 @@ ICacheProvider rateLimitCache
{
}
+ ///
+ public Task>> ListApplicationEmojisAync
+ (
+ Snowflake applicationID,
+ CancellationToken ct = default
+ )
+ {
+ return this.RestHttpClient.GetAsync>
+ (
+ $"applications/{applicationID}/emojis",
+ "items",
+ b => b.WithRateLimitContext(this.RateLimitCache),
+ ct: ct
+ );
+ }
+
+ ///
+ public virtual Task> GetApplicationEmojiAsync
+ (
+ Snowflake applicationID,
+ Snowflake emojiID,
+ CancellationToken ct = default
+ )
+ {
+ return this.RestHttpClient.GetAsync
+ (
+ $"applications/{applicationID}/emojis/{emojiID}",
+ b => b.WithRateLimitContext(this.RateLimitCache),
+ ct: ct
+ );
+ }
+
+ ///
+ public virtual async Task> CreateApplicationEmojiAsync
+ (
+ Snowflake applicationID,
+ string name,
+ Stream image,
+ Optional reason = default,
+ CancellationToken ct = default
+ )
+ {
+ if (image.Length > 256000)
+ {
+ return new NotSupportedError("Image too large (max 256k).");
+ }
+
+ var packImage = await ImagePacker.PackImageAsync(image, ct);
+ if (!packImage.IsSuccess)
+ {
+ return Result.FromError(packImage);
+ }
+
+ var emojiData = packImage.Entity;
+
+ return await this.RestHttpClient.PostAsync
+ (
+ $"applications/{applicationID}/emojis",
+ b => b
+ .AddAuditLogReason(reason)
+ .WithJson
+ (
+ json =>
+ {
+ json.WriteString("name", name);
+ json.WriteString("image", emojiData);
+ }
+ )
+ .WithRateLimitContext(this.RateLimitCache),
+ ct: ct
+ );
+ }
+
+ ///
+ public virtual Task> ModifyApplicationEmojiAsync
+ (
+ Snowflake applicationID,
+ Snowflake emojiID,
+ Optional name = default,
+ Optional reason = default,
+ CancellationToken ct = default
+ )
+ {
+ return this.RestHttpClient.PatchAsync
+ (
+ $"applications/{applicationID}/emojis/{emojiID}",
+ b => b
+ .AddAuditLogReason(reason)
+ .WithJson(
+ json =>
+ {
+ json.Write("name", name, this.JsonOptions);
+ }
+ ).WithRateLimitContext(this.RateLimitCache),
+ ct: ct
+ );
+ }
+
+ ///
+ public virtual Task DeleteApplicationEmojiAsync(Snowflake applicationID, Snowflake emojiID, Optional reason = default, CancellationToken ct = default)
+ {
+ return this.RestHttpClient.DeleteAsync
+ (
+ $"applications/{applicationID}/emojis/{emojiID}",
+ b => b.AddAuditLogReason(reason).WithRateLimitContext(this.RateLimitCache),
+ ct: ct
+ );
+ }
+
///
public virtual Task>> ListGuildEmojisAsync
(