diff --git a/src/Discord.Net.Core/Entities/Emotes/ApplicationEmoteProperties.cs b/src/Discord.Net.Core/Entities/Emotes/ApplicationEmoteProperties.cs
new file mode 100644
index 0000000000..457c338327
--- /dev/null
+++ b/src/Discord.Net.Core/Entities/Emotes/ApplicationEmoteProperties.cs
@@ -0,0 +1,12 @@
+namespace Discord;
+
+///
+/// Represents the properties for an application emote.
+///
+public class ApplicationEmoteProperties
+{
+ ///
+ /// Gets or sets the name of the emote.
+ ///
+ public string Name { get; set; }
+}
diff --git a/src/Discord.Net.Core/Entities/Emotes/Emote.cs b/src/Discord.Net.Core/Entities/Emotes/Emote.cs
index ed5fd682b7..768d04b136 100644
--- a/src/Discord.Net.Core/Entities/Emotes/Emote.cs
+++ b/src/Discord.Net.Core/Entities/Emotes/Emote.cs
@@ -12,8 +12,10 @@ public class Emote : IEmote, ISnowflakeEntity
{
///
public string Name { get; }
+
///
public ulong Id { get; }
+
///
/// Gets whether this emote is animated.
///
@@ -21,8 +23,10 @@ public class Emote : IEmote, ISnowflakeEntity
/// A boolean that determines whether or not this emote is an animated one.
///
public bool Animated { get; }
+
///
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);
+
///
/// Gets the image URL of this emote.
///
@@ -31,6 +35,11 @@ public class Emote : IEmote, ISnowflakeEntity
///
public string Url => CDN.GetEmojiUrl(Id, Animated);
+ ///
+ /// Gets the user who created this emote. if not available.
+ ///
+ public IUser User { get; private set; }
+
///
/// Creates a new instance of .
///
@@ -41,6 +50,14 @@ public Emote(ulong id, string name, bool animated = false)
Animated = animated;
}
+ internal Emote(ulong id, string name, bool animated = false, IUser user = null)
+ {
+ Id = id;
+ Name = name;
+ Animated = animated;
+ User = user;
+ }
+
///
/// Determines whether the specified emote is equal to the current emote.
///
diff --git a/src/Discord.Net.Core/IDiscordClient.cs b/src/Discord.Net.Core/IDiscordClient.cs
index 90562840da..43e77020c1 100644
--- a/src/Discord.Net.Core/IDiscordClient.cs
+++ b/src/Discord.Net.Core/IDiscordClient.cs
@@ -356,5 +356,30 @@ IAsyncEnumerable> GetEntitlementsAsync(int? li
/// The id of the entitlement.
/// The options to be used when sending the request.
Task ConsumeEntitlementAsync(ulong entitlementId, RequestOptions options = null);
+
+ ///
+ /// Gets an emote for the current application.
+ ///
+ public Task GetApplicationEmoteAsync(ulong emoteId, RequestOptions options = null);
+
+ ///
+ /// Gets all emotes for the current application.
+ ///
+ public Task> GetApplicationEmotesAsync(RequestOptions options = null);
+
+ ///
+ /// Modifies an emote for the current application.
+ ///
+ public Task ModifyApplicationEmoteAsync(ulong emoteId, Action args, RequestOptions options = null);
+
+ ///
+ /// Creates an emote for the current application.
+ ///
+ public Task CreateApplicationEmoteAsync(string name, Image image, RequestOptions options = null);
+
+ ///
+ /// Deletes an emote for the current application.
+ ///
+ public Task DeleteApplicationEmoteAsync(ulong emoteId, RequestOptions options = null);
}
}
diff --git a/src/Discord.Net.Rest/API/Common/Emoji.cs b/src/Discord.Net.Rest/API/Common/Emoji.cs
index d35b42ad49..00f666f8df 100644
--- a/src/Discord.Net.Rest/API/Common/Emoji.cs
+++ b/src/Discord.Net.Rest/API/Common/Emoji.cs
@@ -11,16 +11,16 @@ internal class Emoji
public string Name { get; set; }
[JsonProperty("animated")]
- public bool? Animated { get; set; }
+ public Optional Animated { get; set; }
[JsonProperty("roles")]
- public ulong[] Roles { get; set; }
+ public Optional Roles { get; set; }
[JsonProperty("require_colons")]
- public bool RequireColons { get; set; }
+ public Optional RequireColons { get; set; }
[JsonProperty("managed")]
- public bool Managed { get; set; }
+ public Optional Managed { get; set; }
[JsonProperty("user")]
public Optional User { get; set; }
diff --git a/src/Discord.Net.Rest/API/Common/ListApplicationEmojisResponse.cs b/src/Discord.Net.Rest/API/Common/ListApplicationEmojisResponse.cs
new file mode 100644
index 0000000000..1d59f13216
--- /dev/null
+++ b/src/Discord.Net.Rest/API/Common/ListApplicationEmojisResponse.cs
@@ -0,0 +1,9 @@
+using Newtonsoft.Json;
+
+namespace Discord.API;
+
+internal class ListApplicationEmojisResponse
+{
+ [JsonProperty("items")]
+ public Emoji[] Items { get; set; }
+}
diff --git a/src/Discord.Net.Rest/API/Rest/CreateApplicationEmoteParams.cs b/src/Discord.Net.Rest/API/Rest/CreateApplicationEmoteParams.cs
new file mode 100644
index 0000000000..45c0d775ba
--- /dev/null
+++ b/src/Discord.Net.Rest/API/Rest/CreateApplicationEmoteParams.cs
@@ -0,0 +1,12 @@
+using Newtonsoft.Json;
+
+namespace Discord.API.Rest;
+
+internal class CreateApplicationEmoteParams
+{
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ [JsonProperty("image")]
+ public Image Image { get; set; }
+}
diff --git a/src/Discord.Net.Rest/API/Rest/ModifyApplicationEmoteParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyApplicationEmoteParams.cs
new file mode 100644
index 0000000000..b8daffbf95
--- /dev/null
+++ b/src/Discord.Net.Rest/API/Rest/ModifyApplicationEmoteParams.cs
@@ -0,0 +1,9 @@
+using Newtonsoft.Json;
+
+namespace Discord.API.Rest;
+
+internal class ModifyApplicationEmoteParams
+{
+ [JsonProperty("name")]
+ public Optional Name { get; set; }
+}
diff --git a/src/Discord.Net.Rest/BaseDiscordClient.cs b/src/Discord.Net.Rest/BaseDiscordClient.cs
index 372dea35a2..8b95d8b321 100644
--- a/src/Discord.Net.Rest/BaseDiscordClient.cs
+++ b/src/Discord.Net.Rest/BaseDiscordClient.cs
@@ -299,6 +299,22 @@ IAsyncEnumerable> IDiscordClient.GetEntitlemen
///
Task IDiscordClient.ConsumeEntitlementAsync(ulong entitlementId, RequestOptions options) => Task.CompletedTask;
+
+ ///
+ Task IDiscordClient.GetApplicationEmoteAsync(ulong emoteId, RequestOptions options) => Task.FromResult(null);
+
+ ///
+ Task> IDiscordClient.GetApplicationEmotesAsync(RequestOptions options) => Task.FromResult>(ImmutableArray.Create());
+
+ ///
+ Task IDiscordClient.ModifyApplicationEmoteAsync(ulong emoteId, Action args, RequestOptions options) => Task.FromResult(null);
+
+ ///
+ Task IDiscordClient.CreateApplicationEmoteAsync(string name, Image image, RequestOptions options) => Task.FromResult(null);
+
+ ///
+ Task IDiscordClient.DeleteApplicationEmoteAsync(ulong emoteId, RequestOptions options) => Task.CompletedTask;
+
#endregion
}
}
diff --git a/src/Discord.Net.Rest/ClientHelper.cs b/src/Discord.Net.Rest/ClientHelper.cs
index b660697a27..6f7654da8d 100644
--- a/src/Discord.Net.Rest/ClientHelper.cs
+++ b/src/Discord.Net.Rest/ClientHelper.cs
@@ -450,5 +450,48 @@ public static Task ConsumeEntitlementAsync(BaseDiscordClient client, ulong entit
=> client.ApiClient.ConsumeEntitlementAsync(entitlementId, options);
#endregion
+
+ #region Application Emojis
+
+ public static async Task> GetApplicationEmojisAsync(BaseDiscordClient client, RequestOptions options = null)
+ {
+ var model = await client.ApiClient.GetApplicationEmotesAsync(options).ConfigureAwait(false);
+ return model.Items.Select(x => x.ToEmote(client)).ToImmutableArray();
+ }
+
+ public static async Task GetApplicationEmojiAsync(BaseDiscordClient client, ulong emojiId, RequestOptions options = null)
+ {
+ var model = await client.ApiClient.GetApplicationEmoteAsync(emojiId, options).ConfigureAwait(false);
+ return model.ToEmote(client);
+ }
+
+ public static async Task CreateApplicationEmojiAsync(BaseDiscordClient client, string name, Image image, RequestOptions options = null)
+ {
+ var model = await client.ApiClient.CreateApplicationEmoteAsync(new CreateApplicationEmoteParams
+ {
+ Name = name,
+ Image = image.ToModel()
+ }, options).ConfigureAwait(false);
+
+ return model.ToEmote(client);
+ }
+
+ public static async Task ModifyApplicationEmojiAsync(BaseDiscordClient client, ulong emojiId, Action func, RequestOptions options = null)
+ {
+ var args = new ApplicationEmoteProperties();
+ func(args);
+
+ var model = await client.ApiClient.ModifyApplicationEmoteAsync(emojiId, new ModifyApplicationEmoteParams
+ {
+ Name = args.Name,
+ }, options).ConfigureAwait(false);
+
+ return model.ToEmote(client);
+ }
+
+ public static Task DeleteApplicationEmojiAsync(BaseDiscordClient client, ulong emojiId, RequestOptions options = null)
+ => client.ApiClient.DeleteApplicationEmoteAsync(emojiId, options);
+
+ #endregion
}
}
diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs
index e73a8e70f3..beaf015550 100644
--- a/src/Discord.Net.Rest/DiscordRestApiClient.cs
+++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs
@@ -2093,7 +2093,7 @@ public Task> ModifyGuildRolesAsync(ulong guildId, IEnu
}
#endregion
- #region Guild emoji
+ #region Guild Emoji
public Task> GetGuildEmotesAsync(ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
@@ -2845,5 +2845,56 @@ public Task ExpirePollAsync(ulong channelId, ulong messageId, RequestOp
=> SendAsync("POST", () => $"channels/{channelId}/polls/{messageId}/expire", new BucketIds(channelId: channelId), options: options);
#endregion
+
+ #region App Emojis
+
+ public Task CreateApplicationEmoteAsync(CreateApplicationEmoteParams args, RequestOptions options = null)
+ {
+ Preconditions.NotNull(args, nameof(args));
+ Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name));
+ Preconditions.NotNull(args.Image.Stream, nameof(args.Image));
+ options = RequestOptions.CreateOrClone(options);
+
+ var ids = new BucketIds();
+ return SendJsonAsync("POST", () => $"applications/{CurrentApplicationId}/emojis", args, ids, options: options);
+ }
+
+ public Task ModifyApplicationEmoteAsync(ulong emoteId, ModifyApplicationEmoteParams args, RequestOptions options = null)
+ {
+ Preconditions.NotEqual(emoteId, 0, nameof(emoteId));
+ Preconditions.NotNull(args, nameof(args));
+ options = RequestOptions.CreateOrClone(options);
+
+ var ids = new BucketIds();
+ return SendJsonAsync("PATCH", () => $"applications/{CurrentApplicationId}/emojis/{emoteId}", args, ids, options: options);
+ }
+
+ public Task DeleteApplicationEmoteAsync(ulong emoteId, RequestOptions options = null)
+ {
+ Preconditions.NotEqual(emoteId, 0, nameof(emoteId));
+ options = RequestOptions.CreateOrClone(options);
+
+ var ids = new BucketIds();
+ return SendAsync("DELETE", () => $"applications/{CurrentApplicationId}/emojis/{emoteId}", ids, options: options);
+ }
+
+ public Task GetApplicationEmoteAsync(ulong emoteId, RequestOptions options = null)
+ {
+ Preconditions.NotEqual(emoteId, 0, nameof(emoteId));
+ options = RequestOptions.CreateOrClone(options);
+
+ var ids = new BucketIds();
+ return SendAsync("GET", () => $"applications/{CurrentApplicationId}/emojis/{emoteId}", ids, options: options);
+ }
+
+ public Task GetApplicationEmotesAsync(RequestOptions options = null)
+ {
+ options = RequestOptions.CreateOrClone(options);
+
+ var ids = new BucketIds();
+ return SendAsync("GET", () => $"applications/{CurrentApplicationId}/emojis", ids, options: options);
+ }
+
+ #endregion
}
}
diff --git a/src/Discord.Net.Rest/DiscordRestClient.cs b/src/Discord.Net.Rest/DiscordRestClient.cs
index 0d5ae05843..404e84af1c 100644
--- a/src/Discord.Net.Rest/DiscordRestClient.cs
+++ b/src/Discord.Net.Rest/DiscordRestClient.cs
@@ -300,6 +300,26 @@ public Task> GetSKUsAsync(RequestOptions options = null
public Task ConsumeEntitlementAsync(ulong entitlementId, RequestOptions options = null)
=> ClientHelper.ConsumeEntitlementAsync(this, entitlementId, options);
+ ///
+ public Task GetApplicationEmoteAsync(ulong emoteId, RequestOptions options = null)
+ => ClientHelper.GetApplicationEmojiAsync(this, emoteId, options);
+
+ ///
+ public Task> GetApplicationEmotesAsync(RequestOptions options = null)
+ => ClientHelper.GetApplicationEmojisAsync(this, options);
+
+ ///
+ public Task ModifyApplicationEmoteAsync(ulong emoteId, Action args, RequestOptions options = null)
+ => ClientHelper.ModifyApplicationEmojiAsync(this, emoteId, args, options);
+
+ ///
+ public Task CreateApplicationEmoteAsync(string name, Image image, RequestOptions options = null)
+ => ClientHelper.CreateApplicationEmojiAsync(this, name, image, options);
+
+ ///
+ public Task DeleteApplicationEmoteAsync(ulong emoteId, RequestOptions options = null)
+ => ClientHelper.DeleteApplicationEmojiAsync(this, emoteId, options);
+
#endregion
#region IDiscordClient
diff --git a/src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboardingPromptOption.cs b/src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboardingPromptOption.cs
index 513c836cd4..768e685308 100644
--- a/src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboardingPromptOption.cs
+++ b/src/Discord.Net.Rest/Entities/Guilds/Onboarding/RestGuildOnboardingPromptOption.cs
@@ -36,7 +36,7 @@ internal RestGuildOnboardingPromptOption(BaseDiscordClient discord, ulong id, Mo
if (model.Emoji.Id.HasValue)
{
- Emoji = new Emote(model.Emoji.Id.Value, model.Emoji.Name, model.Emoji.Animated ?? false);
+ Emoji = new Emote(model.Emoji.Id.Value, model.Emoji.Name, model.Emoji.Animated.GetValueOrDefault(false));
}
else if (!string.IsNullOrWhiteSpace(model.Emoji.Name))
{
diff --git a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs
index 3e7ec81bbb..e6a510a24c 100644
--- a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs
+++ b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
@@ -13,13 +14,21 @@ public static IEmote ToIEmote(this API.Emoji model)
return new Emoji(model.Name);
}
+ public static Emote ToEmote(this API.Emoji model, BaseDiscordClient discord = null)
+ => new(model.Id.GetValueOrDefault(),
+ model.Name,
+ model.Animated.GetValueOrDefault(false),
+ model.User.IsSpecified ?
+ RestUser.Create(discord, model.User.Value)
+ : null);
+
public static GuildEmote ToEntity(this API.Emoji model)
=> new GuildEmote(model.Id.Value,
model.Name,
- model.Animated.GetValueOrDefault(),
- model.Managed,
- model.RequireColons,
- ImmutableArray.Create(model.Roles),
+ model.Animated.GetValueOrDefault(false),
+ model.Managed.GetValueOrDefault(false),
+ model.RequireColons.GetValueOrDefault(false),
+ model.Roles.GetValueOrDefault([]).ToImmutableArray(),
model.User.IsSpecified ? model.User.Value.Id : null,
model.IsAvailable.ToNullable());
diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs
index 06179e10ea..d4754d7dd2 100644
--- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs
+++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs
@@ -451,6 +451,26 @@ public Task> GetSKUsAsync(RequestOptions options = null
public Task ConsumeEntitlementAsync(ulong entitlementId, RequestOptions options = null)
=> ClientHelper.ConsumeEntitlementAsync(this, entitlementId, options);
+ ///
+ public Task GetApplicationEmoteAsync(ulong emoteId, RequestOptions options = null)
+ => ClientHelper.GetApplicationEmojiAsync(this, emoteId, options);
+
+ ///
+ public Task> GetApplicationEmotesAsync(RequestOptions options = null)
+ => ClientHelper.GetApplicationEmojisAsync(this, options);
+
+ ///
+ public Task ModifyApplicationEmoteAsync(ulong emoteId, Action args, RequestOptions options = null)
+ => ClientHelper.ModifyApplicationEmojiAsync(this, emoteId, args, options);
+
+ ///
+ public Task CreateApplicationEmoteAsync(string name, Image image, RequestOptions options = null)
+ => ClientHelper.CreateApplicationEmojiAsync(this, name, image, options);
+
+ ///
+ public Task DeleteApplicationEmoteAsync(ulong emoteId, RequestOptions options = null)
+ => ClientHelper.DeleteApplicationEmojiAsync(this, emoteId, options);
+
///
/// Gets entitlements from cache.
///
diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboardingPromptOption.cs b/src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboardingPromptOption.cs
index 4e96a9f6d9..992d08696c 100644
--- a/src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboardingPromptOption.cs
+++ b/src/Discord.Net.WebSocket/Entities/Guilds/Onboarding/SocketGuildOnboardingPromptOption.cs
@@ -47,7 +47,7 @@ internal SocketGuildOnboardingPromptOption(DiscordSocketClient discord, ulong id
if (model.Emoji.Id.HasValue)
{
- Emoji = new Emote(model.Emoji.Id.Value, model.Emoji.Name, model.Emoji.Animated ?? false);
+ Emoji = new Emote(model.Emoji.Id.Value, model.Emoji.Name, model.Emoji.Animated.GetValueOrDefault(false));
}
else if (!string.IsNullOrWhiteSpace(model.Emoji.Name))
{