From 838d60e2c2f72b7cd6de1133ff608e358003fed2 Mon Sep 17 00:00:00 2001 From: Christopher F Date: Mon, 31 Oct 2016 19:50:38 -0400 Subject: [PATCH] Add API model for Reaction, implement REST methods for reactions --- src/Discord.Net.Core/API/Common/Reaction.cs | 20 +++++++++ .../API/DiscordRestApiClient.cs | 42 +++++++++++++++++++ .../API/Rest/GetReactionUsersParams.cs | 8 ++++ .../Entities/Messages/IUserMessage.cs | 13 +++++- src/Discord.Net.Core/Utils/Preconditions.cs | 1 + .../Entities/Messages/MessageHelper.cs | 23 ++++++++++ .../Entities/Messages/RestUserMessage.cs | 14 +++++++ .../Entities/Messages/RpcUserMessage.cs | 13 ++++++ .../Entities/Messages/SocketUserMessage.cs | 13 ++++++ 9 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 src/Discord.Net.Core/API/Common/Reaction.cs create mode 100644 src/Discord.Net.Core/API/Rest/GetReactionUsersParams.cs diff --git a/src/Discord.Net.Core/API/Common/Reaction.cs b/src/Discord.Net.Core/API/Common/Reaction.cs new file mode 100644 index 000000000..69dbf4b0c --- /dev/null +++ b/src/Discord.Net.Core/API/Common/Reaction.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace Discord.API.Common +{ + public class Reaction + { + [JsonProperty("user_id")] + public ulong UserId { get; set; } + [JsonProperty("message_id")] + public ulong MessageId { get; set; } + [JsonProperty("emoji")] + public Emoji Emoji { get; set; } + [JsonProperty("channel_id")] + public ulong ChannelId { get; set; } + } +} diff --git a/src/Discord.Net.Core/API/DiscordRestApiClient.cs b/src/Discord.Net.Core/API/DiscordRestApiClient.cs index ac18e8ace..4d85c68b2 100644 --- a/src/Discord.Net.Core/API/DiscordRestApiClient.cs +++ b/src/Discord.Net.Core/API/DiscordRestApiClient.cs @@ -512,6 +512,48 @@ namespace Discord.API var ids = new BucketIds(channelId: channelId); return await SendJsonAsync("PATCH", () => $"channels/{channelId}/messages/{messageId}", args, ids, clientBucketId: ClientBucket.SendEditId, options: options).ConfigureAwait(false); } + public async Task AddReactionAsync(ulong channelId, ulong messageId, string emoji, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + Preconditions.NotNullOrWhitespace(emoji, nameof(emoji)); + + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + + await SendAsync("PUT", () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}/@me", ids, options: options).ConfigureAwait(false); + } + public async Task RemoveReactionAsync(ulong channelId, ulong messageId, ulong userId, string emoji, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + Preconditions.NotNullOrWhitespace(emoji, nameof(emoji)); + + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + + await SendAsync("DELETE", () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}/{userId}", ids, options: options).ConfigureAwait(false); + } + public async Task> GetReactionUsersAsync(ulong channelId, ulong messageId, string emoji, GetReactionUsersParams args, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + Preconditions.NotNullOrWhitespace(emoji, nameof(emoji)); + Preconditions.NotNull(args, nameof(args)); + Preconditions.GreaterThan(args.Limit, 0, nameof(args.Limit)); + Preconditions.AtMost(args.Limit, DiscordConfig.MaxUsersPerBatch, nameof(args.Limit)); + Preconditions.GreaterThan(args.AfterUserId, 0, nameof(args.AfterUserId)); + options = RequestOptions.CreateOrClone(options); + + int limit = args.Limit.GetValueOrDefault(int.MaxValue); + ulong afterUserId = args.AfterUserId.GetValueOrDefault(0); + + var ids = new BucketIds(channelId: channelId); + Expression> endpoint = () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}"; + return await SendAsync>("GET", endpoint, ids, options: options).ConfigureAwait(false); + } public async Task AckMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null) { Preconditions.NotEqual(channelId, 0, nameof(channelId)); diff --git a/src/Discord.Net.Core/API/Rest/GetReactionUsersParams.cs b/src/Discord.Net.Core/API/Rest/GetReactionUsersParams.cs new file mode 100644 index 000000000..bb9b22ab8 --- /dev/null +++ b/src/Discord.Net.Core/API/Rest/GetReactionUsersParams.cs @@ -0,0 +1,8 @@ +namespace Discord.API.Rest +{ + public class GetReactionUsersParams + { + public Optional Limit { get; set; } + public Optional AfterUserId { get; set; } + } +} diff --git a/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs b/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs index a9dc4735c..3a7b5821a 100644 --- a/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs +++ b/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs @@ -1,5 +1,6 @@ using Discord.API.Rest; using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace Discord @@ -12,7 +13,17 @@ namespace Discord Task PinAsync(RequestOptions options = null); /// Removes this message from its channel's pinned messages. Task UnpinAsync(RequestOptions options = null); - + + /// Adds a reaction to this message. + Task AddReactionAsync(Emoji emoji, RequestOptions options = null); + /// Adds a reaction to this message. + Task AddReactionAsync(string emoji, RequestOptions options = null); + /// Removes a reaction from message. + Task RemoveReactionAsync(Emoji emoji, IUser user, RequestOptions options = null); + /// Removes a reaction from this message. + Task RemoveReactionAsync(string emoji, IUser user, RequestOptions options = null); + Task> GetReactionUsersAsync(string emoji, Action func, RequestOptions options = null); + /// Transforms this message's text into a human readable form by resolving its tags. string Resolve( TagHandling userHandling = TagHandling.Name, diff --git a/src/Discord.Net.Core/Utils/Preconditions.cs b/src/Discord.Net.Core/Utils/Preconditions.cs index 14c9db24d..2c6ea2417 100644 --- a/src/Discord.Net.Core/Utils/Preconditions.cs +++ b/src/Discord.Net.Core/Utils/Preconditions.cs @@ -45,6 +45,7 @@ namespace Discord throw new ArgumentException("Argument cannot be blank.", name); } } + //Numerics public static void NotEqual(sbyte obj, sbyte value, string name) { if (obj == value) throw new ArgumentOutOfRangeException(name); } diff --git a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs index 358f6f5a9..602a790a5 100644 --- a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs +++ b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs @@ -23,6 +23,29 @@ namespace Discord.Rest await client.ApiClient.DeleteMessageAsync(msg.Channel.Id, msg.Id, options).ConfigureAwait(false); } + public static async Task AddReactionAsync(IMessage msg, Emoji emoji, BaseDiscordClient client, RequestOptions options) + => await AddReactionAsync(msg, $"{emoji.Name}:{emoji.Id}", client, options).ConfigureAwait(false); + public static async Task AddReactionAsync(IMessage msg, string emoji, BaseDiscordClient client, RequestOptions options) + { + await client.ApiClient.AddReactionAsync(msg.Channel.Id, msg.Id, emoji, options).ConfigureAwait(false); + } + + public static async Task RemoveReactionAsync(IMessage msg, IUser user, Emoji emoji, BaseDiscordClient client, RequestOptions options) + => await RemoveReactionAsync(msg, user, $"{emoji.Name}:{emoji.Id}", client, options).ConfigureAwait(false); + public static async Task RemoveReactionAsync(IMessage msg, IUser user, string emoji, BaseDiscordClient client, + RequestOptions options) + { + await client.ApiClient.RemoveReactionAsync(msg.Channel.Id, msg.Id, user.Id, emoji, options); + } + + public static async Task> GetReactionUsersAsync(IMessage msg, string emoji, + Action func, BaseDiscordClient client, RequestOptions options) + { + var args = new GetReactionUsersParams(); + func(args); + return (await client.ApiClient.GetReactionUsersAsync(msg.Channel.Id, msg.Id, emoji, args, options).ConfigureAwait(false)).Select(u => u as IUser).Where(u => u != null).ToImmutableArray(); + } + public static async Task PinAsync(IMessage msg, BaseDiscordClient client, RequestOptions options) { diff --git a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs index d3d3b6fce..66d270fdd 100644 --- a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs +++ b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs @@ -117,6 +117,20 @@ namespace Discord.Rest Update(model); } + public Task AddReactionAsync(Emoji emoji, RequestOptions options) + => MessageHelper.AddReactionAsync(this, emoji, Discord, options); + public Task AddReactionAsync(string emoji, RequestOptions options) + => MessageHelper.AddReactionAsync(this, emoji, Discord, options); + + public Task RemoveReactionAsync(Emoji emoji, IUser user, RequestOptions options) + => MessageHelper.RemoveReactionAsync(this, user, emoji, Discord, options); + public Task RemoveReactionAsync(string emoji, IUser user, RequestOptions options) + => MessageHelper.RemoveReactionAsync(this, user, emoji, Discord, options); + + public Task> GetReactionUsersAsync(string emoji, Action func, RequestOptions options) + => MessageHelper.GetReactionUsersAsync(this, emoji, func, Discord, options); + + public Task PinAsync(RequestOptions options) => MessageHelper.PinAsync(this, Discord, options); public Task UnpinAsync(RequestOptions options) diff --git a/src/Discord.Net.Rpc/Entities/Messages/RpcUserMessage.cs b/src/Discord.Net.Rpc/Entities/Messages/RpcUserMessage.cs index edfa60484..01cff3611 100644 --- a/src/Discord.Net.Rpc/Entities/Messages/RpcUserMessage.cs +++ b/src/Discord.Net.Rpc/Entities/Messages/RpcUserMessage.cs @@ -101,6 +101,19 @@ namespace Discord.Rpc public Task ModifyAsync(Action func, RequestOptions options) => MessageHelper.ModifyAsync(this, Discord, func, options); + public Task AddReactionAsync(Emoji emoji, RequestOptions options) + => MessageHelper.AddReactionAsync(this, emoji, Discord, options); + public Task AddReactionAsync(string emoji, RequestOptions options) + => MessageHelper.AddReactionAsync(this, emoji, Discord, options); + + public Task RemoveReactionAsync(Emoji emoji, IUser user, RequestOptions options) + => MessageHelper.RemoveReactionAsync(this, user, emoji, Discord, options); + public Task RemoveReactionAsync(string emoji, IUser user, RequestOptions options) + => MessageHelper.RemoveReactionAsync(this, user, emoji, Discord, options); + + public Task> GetReactionUsersAsync(string emoji, Action func, RequestOptions options) + => MessageHelper.GetReactionUsersAsync(this, emoji, func, Discord, options); + public Task PinAsync(RequestOptions options) => MessageHelper.PinAsync(this, Discord, options); public Task UnpinAsync(RequestOptions options) diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs index db9b82ebd..4174ff899 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs @@ -113,6 +113,19 @@ namespace Discord.WebSocket public Task ModifyAsync(Action func, RequestOptions options = null) => MessageHelper.ModifyAsync(this, Discord, func, options); + public Task AddReactionAsync(Emoji emoji, RequestOptions options) + => MessageHelper.AddReactionAsync(this, emoji, Discord, options); + public Task AddReactionAsync(string emoji, RequestOptions options) + => MessageHelper.AddReactionAsync(this, emoji, Discord, options); + + public Task RemoveReactionAsync(Emoji emoji, IUser user, RequestOptions options) + => MessageHelper.RemoveReactionAsync(this, user, emoji, Discord, options); + public Task RemoveReactionAsync(string emoji, IUser user, RequestOptions options) + => MessageHelper.RemoveReactionAsync(this, user, emoji, Discord, options); + + public Task> GetReactionUsersAsync(string emoji, Action func, RequestOptions options) + => MessageHelper.GetReactionUsersAsync(this, emoji, func, Discord, options); + public Task PinAsync(RequestOptions options = null) => MessageHelper.PinAsync(this, Discord, options); public Task UnpinAsync(RequestOptions options = null)