Skip to content

Commit

Permalink
uh yes pls (#2963)
Browse files Browse the repository at this point in the history
  • Loading branch information
Misha-133 committed Jul 20, 2024
1 parent 8b6be64 commit 26bb789
Show file tree
Hide file tree
Showing 15 changed files with 254 additions and 11 deletions.
12 changes: 12 additions & 0 deletions src/Discord.Net.Core/Entities/Emotes/ApplicationEmoteProperties.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Discord;

/// <summary>
/// Represents the properties for an application emote.
/// </summary>
public class ApplicationEmoteProperties
{
/// <summary>
/// Gets or sets the name of the emote.
/// </summary>
public string Name { get; set; }
}
17 changes: 17 additions & 0 deletions src/Discord.Net.Core/Entities/Emotes/Emote.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,21 @@ public class Emote : IEmote, ISnowflakeEntity
{
/// <inheritdoc />
public string Name { get; }

/// <inheritdoc />
public ulong Id { get; }

/// <summary>
/// Gets whether this emote is animated.
/// </summary>
/// <returns>
/// A boolean that determines whether or not this emote is an animated one.
/// </returns>
public bool Animated { get; }

/// <inheritdoc />
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);

/// <summary>
/// Gets the image URL of this emote.
/// </summary>
Expand All @@ -31,6 +35,11 @@ public class Emote : IEmote, ISnowflakeEntity
/// </returns>
public string Url => CDN.GetEmojiUrl(Id, Animated);

/// <summary>
/// Gets the user who created this emote. <see langword="null" /> if not available.
/// </summary>
public IUser User { get; private set; }

/// <summary>
/// Creates a new instance of <see cref="Emote" />.
/// </summary>
Expand All @@ -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;
}

/// <summary>
/// Determines whether the specified emote is equal to the current emote.
/// </summary>
Expand Down
25 changes: 25 additions & 0 deletions src/Discord.Net.Core/IDiscordClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -356,5 +356,30 @@ IAsyncEnumerable<IReadOnlyCollection<IEntitlement>> GetEntitlementsAsync(int? li
/// <param name="entitlementId">The id of the entitlement.</param>
/// <param name="options">The options to be used when sending the request.</param>
Task ConsumeEntitlementAsync(ulong entitlementId, RequestOptions options = null);

/// <summary>
/// Gets an emote for the current application.
/// </summary>
public Task<Emote> GetApplicationEmoteAsync(ulong emoteId, RequestOptions options = null);

/// <summary>
/// Gets all emotes for the current application.
/// </summary>
public Task<IReadOnlyCollection<Emote>> GetApplicationEmotesAsync(RequestOptions options = null);

/// <summary>
/// Modifies an emote for the current application.
/// </summary>
public Task<Emote> ModifyApplicationEmoteAsync(ulong emoteId, Action<ApplicationEmoteProperties> args, RequestOptions options = null);

/// <summary>
/// Creates an emote for the current application.
/// </summary>
public Task<Emote> CreateApplicationEmoteAsync(string name, Image image, RequestOptions options = null);

/// <summary>
/// Deletes an emote for the current application.
/// </summary>
public Task DeleteApplicationEmoteAsync(ulong emoteId, RequestOptions options = null);
}
}
8 changes: 4 additions & 4 deletions src/Discord.Net.Rest/API/Common/Emoji.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ internal class Emoji
public string Name { get; set; }

[JsonProperty("animated")]
public bool? Animated { get; set; }
public Optional<bool> Animated { get; set; }

[JsonProperty("roles")]
public ulong[] Roles { get; set; }
public Optional<ulong[]> Roles { get; set; }

[JsonProperty("require_colons")]
public bool RequireColons { get; set; }
public Optional<bool> RequireColons { get; set; }

[JsonProperty("managed")]
public bool Managed { get; set; }
public Optional<bool> Managed { get; set; }

[JsonProperty("user")]
public Optional<User> User { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Newtonsoft.Json;

namespace Discord.API;

internal class ListApplicationEmojisResponse
{
[JsonProperty("items")]
public Emoji[] Items { get; set; }
}
12 changes: 12 additions & 0 deletions src/Discord.Net.Rest/API/Rest/CreateApplicationEmoteParams.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
9 changes: 9 additions & 0 deletions src/Discord.Net.Rest/API/Rest/ModifyApplicationEmoteParams.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Newtonsoft.Json;

namespace Discord.API.Rest;

internal class ModifyApplicationEmoteParams
{
[JsonProperty("name")]
public Optional<string> Name { get; set; }
}
16 changes: 16 additions & 0 deletions src/Discord.Net.Rest/BaseDiscordClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,22 @@ IAsyncEnumerable<IReadOnlyCollection<IEntitlement>> IDiscordClient.GetEntitlemen
/// </summary>
Task IDiscordClient.ConsumeEntitlementAsync(ulong entitlementId, RequestOptions options) => Task.CompletedTask;


/// <inheritdoc />
Task<Emote> IDiscordClient.GetApplicationEmoteAsync(ulong emoteId, RequestOptions options) => Task.FromResult<Emote>(null);

/// <inheritdoc />
Task<IReadOnlyCollection<Emote>> IDiscordClient.GetApplicationEmotesAsync(RequestOptions options) => Task.FromResult<IReadOnlyCollection<Emote>>(ImmutableArray.Create<Emote>());

/// <inheritdoc />
Task<Emote> IDiscordClient.ModifyApplicationEmoteAsync(ulong emoteId, Action<ApplicationEmoteProperties> args, RequestOptions options) => Task.FromResult<Emote>(null);

/// <inheritdoc />
Task<Emote> IDiscordClient.CreateApplicationEmoteAsync(string name, Image image, RequestOptions options) => Task.FromResult<Emote>(null);

/// <inheritdoc />
Task IDiscordClient.DeleteApplicationEmoteAsync(ulong emoteId, RequestOptions options) => Task.CompletedTask;

#endregion
}
}
43 changes: 43 additions & 0 deletions src/Discord.Net.Rest/ClientHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<IReadOnlyCollection<Emote>> 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<Emote> 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<Emote> 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<Emote> ModifyApplicationEmojiAsync(BaseDiscordClient client, ulong emojiId, Action<ApplicationEmoteProperties> 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
}
}
53 changes: 52 additions & 1 deletion src/Discord.Net.Rest/DiscordRestApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2093,7 +2093,7 @@ public Task<IReadOnlyCollection<Role>> ModifyGuildRolesAsync(ulong guildId, IEnu
}
#endregion

#region Guild emoji
#region Guild Emoji
public Task<IReadOnlyCollection<Emoji>> GetGuildEmotesAsync(ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Expand Down Expand Up @@ -2845,5 +2845,56 @@ public Task<Message> ExpirePollAsync(ulong channelId, ulong messageId, RequestOp
=> SendAsync<Message>("POST", () => $"channels/{channelId}/polls/{messageId}/expire", new BucketIds(channelId: channelId), options: options);

#endregion

#region App Emojis

public Task<Emoji> 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<Emoji>("POST", () => $"applications/{CurrentApplicationId}/emojis", args, ids, options: options);
}

public Task<Emoji> 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<Emoji>("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<Emoji> GetApplicationEmoteAsync(ulong emoteId, RequestOptions options = null)
{
Preconditions.NotEqual(emoteId, 0, nameof(emoteId));
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds();
return SendAsync<Emoji>("GET", () => $"applications/{CurrentApplicationId}/emojis/{emoteId}", ids, options: options);
}

public Task<ListApplicationEmojisResponse> GetApplicationEmotesAsync(RequestOptions options = null)
{
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds();
return SendAsync<ListApplicationEmojisResponse>("GET", () => $"applications/{CurrentApplicationId}/emojis", ids, options: options);
}

#endregion
}
}
20 changes: 20 additions & 0 deletions src/Discord.Net.Rest/DiscordRestClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,26 @@ public Task<IReadOnlyCollection<SKU>> GetSKUsAsync(RequestOptions options = null
public Task ConsumeEntitlementAsync(ulong entitlementId, RequestOptions options = null)
=> ClientHelper.ConsumeEntitlementAsync(this, entitlementId, options);

/// <inheritdoc />
public Task<Emote> GetApplicationEmoteAsync(ulong emoteId, RequestOptions options = null)
=> ClientHelper.GetApplicationEmojiAsync(this, emoteId, options);

/// <inheritdoc />
public Task<IReadOnlyCollection<Emote>> GetApplicationEmotesAsync(RequestOptions options = null)
=> ClientHelper.GetApplicationEmojisAsync(this, options);

/// <inheritdoc />
public Task<Emote> ModifyApplicationEmoteAsync(ulong emoteId, Action<ApplicationEmoteProperties> args, RequestOptions options = null)
=> ClientHelper.ModifyApplicationEmojiAsync(this, emoteId, args, options);

/// <inheritdoc />
public Task<Emote> CreateApplicationEmoteAsync(string name, Image image, RequestOptions options = null)
=> ClientHelper.CreateApplicationEmojiAsync(this, name, image, options);

/// <inheritdoc />
public Task DeleteApplicationEmoteAsync(ulong emoteId, RequestOptions options = null)
=> ClientHelper.DeleteApplicationEmojiAsync(this, emoteId, options);

#endregion

#region IDiscordClient
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down
17 changes: 13 additions & 4 deletions src/Discord.Net.Rest/Extensions/EntityExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
Expand All @@ -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());

Expand Down
20 changes: 20 additions & 0 deletions src/Discord.Net.WebSocket/DiscordSocketClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,26 @@ public Task<IReadOnlyCollection<SKU>> GetSKUsAsync(RequestOptions options = null
public Task ConsumeEntitlementAsync(ulong entitlementId, RequestOptions options = null)
=> ClientHelper.ConsumeEntitlementAsync(this, entitlementId, options);

/// <inheritdoc />
public Task<Emote> GetApplicationEmoteAsync(ulong emoteId, RequestOptions options = null)
=> ClientHelper.GetApplicationEmojiAsync(this, emoteId, options);

/// <inheritdoc />
public Task<IReadOnlyCollection<Emote>> GetApplicationEmotesAsync(RequestOptions options = null)
=> ClientHelper.GetApplicationEmojisAsync(this, options);

/// <inheritdoc />
public Task<Emote> ModifyApplicationEmoteAsync(ulong emoteId, Action<ApplicationEmoteProperties> args, RequestOptions options = null)
=> ClientHelper.ModifyApplicationEmojiAsync(this, emoteId, args, options);

/// <inheritdoc />
public Task<Emote> CreateApplicationEmoteAsync(string name, Image image, RequestOptions options = null)
=> ClientHelper.CreateApplicationEmojiAsync(this, name, image, options);

/// <inheritdoc />
public Task DeleteApplicationEmoteAsync(ulong emoteId, RequestOptions options = null)
=> ClientHelper.DeleteApplicationEmojiAsync(this, emoteId, options);

/// <summary>
/// Gets entitlements from cache.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down

0 comments on commit 26bb789

Please sign in to comment.