* Cleaned up and refactored slightly * Resolves #971 * Adds support for default avatars and resolves #971 * Amendment * Final amendment * Paginating reactions * Amendments based on feedback * Further amendment based on review * Final(?) amendment * Removes default limit and after user id * Removes fromUserId; cleans up model creation; replaces function with individual parameterspull/1020/merge
@@ -1,4 +1,4 @@ | |||||
using System.Reflection; | |||||
using System.Reflection; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
@@ -20,6 +20,7 @@ namespace Discord | |||||
public const int MaxMessagesPerBatch = 100; | public const int MaxMessagesPerBatch = 100; | ||||
public const int MaxUsersPerBatch = 1000; | public const int MaxUsersPerBatch = 1000; | ||||
public const int MaxGuildsPerBatch = 100; | public const int MaxGuildsPerBatch = 100; | ||||
public const int MaxUserReactionsPerBatch = 100; | |||||
public const int MaxAuditLogEntriesPerBatch = 100; | public const int MaxAuditLogEntriesPerBatch = 100; | ||||
/// <summary> Gets or sets how a request should act in the case of an error, by default. </summary> | /// <summary> Gets or sets how a request should act in the case of an error, by default. </summary> | ||||
@@ -1,4 +1,4 @@ | |||||
using System; | |||||
using System; | |||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
@@ -23,7 +23,7 @@ namespace Discord | |||||
/// <summary> Removes all reactions from this message. </summary> | /// <summary> Removes all reactions from this message. </summary> | ||||
Task RemoveAllReactionsAsync(RequestOptions options = null); | Task RemoveAllReactionsAsync(RequestOptions options = null); | ||||
/// <summary> Gets all users that reacted to a message with a given emote </summary> | /// <summary> Gets all users that reacted to a message with a given emote </summary> | ||||
Task<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emoji, int limit = 100, ulong? afterUserId = null, RequestOptions options = null); | |||||
IAsyncEnumerable<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emoji, int limit, RequestOptions options = null); | |||||
/// <summary> Transforms this message's text into a human readable form by resolving its tags. </summary> | /// <summary> Transforms this message's text into a human readable form by resolving its tags. </summary> | ||||
string Resolve( | string Resolve( | ||||
@@ -1,4 +1,4 @@ | |||||
namespace Discord.API.Rest | |||||
namespace Discord.API.Rest | |||||
{ | { | ||||
internal class GetReactionUsersParams | internal class GetReactionUsersParams | ||||
{ | { | ||||
@@ -618,11 +618,11 @@ namespace Discord.API | |||||
Preconditions.NotNullOrWhitespace(emoji, nameof(emoji)); | Preconditions.NotNullOrWhitespace(emoji, nameof(emoji)); | ||||
Preconditions.NotNull(args, nameof(args)); | Preconditions.NotNull(args, nameof(args)); | ||||
Preconditions.GreaterThan(args.Limit, 0, nameof(args.Limit)); | Preconditions.GreaterThan(args.Limit, 0, nameof(args.Limit)); | ||||
Preconditions.AtMost(args.Limit, DiscordConfig.MaxUsersPerBatch, nameof(args.Limit)); | |||||
Preconditions.AtMost(args.Limit, DiscordConfig.MaxUserReactionsPerBatch, nameof(args.Limit)); | |||||
Preconditions.GreaterThan(args.AfterUserId, 0, nameof(args.AfterUserId)); | Preconditions.GreaterThan(args.AfterUserId, 0, nameof(args.AfterUserId)); | ||||
options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
int limit = args.Limit.GetValueOrDefault(int.MaxValue); | |||||
int limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxUserReactionsPerBatch); | |||||
ulong afterUserId = args.AfterUserId.GetValueOrDefault(0); | ulong afterUserId = args.AfterUserId.GetValueOrDefault(0); | ||||
var ids = new BucketIds(channelId: channelId); | var ids = new BucketIds(channelId: channelId); | ||||
@@ -46,13 +46,38 @@ namespace Discord.Rest | |||||
await client.ApiClient.RemoveAllReactionsAsync(msg.Channel.Id, msg.Id, options); | await client.ApiClient.RemoveAllReactionsAsync(msg.Channel.Id, msg.Id, options); | ||||
} | } | ||||
public static async Task<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IMessage msg, IEmote emote, | |||||
Action<GetReactionUsersParams> func, BaseDiscordClient client, RequestOptions options) | |||||
public static IAsyncEnumerable<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IMessage msg, IEmote emote, | |||||
int? limit, BaseDiscordClient client, RequestOptions options) | |||||
{ | { | ||||
var args = new GetReactionUsersParams(); | |||||
func(args); | |||||
string emoji = (emote is Emote e ? $"{e.Name}:{e.Id}" : emote.Name); | |||||
return (await client.ApiClient.GetReactionUsersAsync(msg.Channel.Id, msg.Id, emoji, args, options).ConfigureAwait(false)).Select(u => RestUser.Create(client, u)).ToImmutableArray(); | |||||
Preconditions.NotNull(emote, nameof(emote)); | |||||
var emoji = (emote is Emote e ? $"{e.Name}:{e.Id}" : emote.Name); | |||||
return new PagedAsyncEnumerable<IUser>( | |||||
DiscordConfig.MaxUserReactionsPerBatch, | |||||
async (info, ct) => | |||||
{ | |||||
var args = new GetReactionUsersParams | |||||
{ | |||||
Limit = info.PageSize | |||||
}; | |||||
if (info.Position != null) | |||||
args.AfterUserId = info.Position.Value; | |||||
var models = await client.ApiClient.GetReactionUsersAsync(msg.Channel.Id, msg.Id, emoji, args, options).ConfigureAwait(false); | |||||
return models.Select(x => RestUser.Create(client, x)).ToImmutableArray(); | |||||
}, | |||||
nextPage: (info, lastPage) => | |||||
{ | |||||
if (lastPage.Count != DiscordConfig.MaxUsersPerBatch) | |||||
return false; | |||||
info.Position = lastPage.Max(x => x.Id); | |||||
return true; | |||||
}, | |||||
count: limit | |||||
); | |||||
} | } | ||||
public static async Task PinAsync(IMessage msg, BaseDiscordClient client, | public static async Task PinAsync(IMessage msg, BaseDiscordClient client, | ||||
@@ -136,8 +136,8 @@ namespace Discord.Rest | |||||
=> MessageHelper.RemoveReactionAsync(this, user, emote, Discord, options); | => MessageHelper.RemoveReactionAsync(this, user, emote, Discord, options); | ||||
public Task RemoveAllReactionsAsync(RequestOptions options = null) | public Task RemoveAllReactionsAsync(RequestOptions options = null) | ||||
=> MessageHelper.RemoveAllReactionsAsync(this, Discord, options); | => MessageHelper.RemoveAllReactionsAsync(this, Discord, options); | ||||
public Task<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emote, int limit = 100, ulong? afterUserId = null, RequestOptions options = null) | |||||
=> MessageHelper.GetReactionUsersAsync(this, emote, x => { x.Limit = limit; x.AfterUserId = afterUserId ?? Optional.Create<ulong>(); }, Discord, options); | |||||
public IAsyncEnumerable<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emote, int limit, RequestOptions options = null) | |||||
=> MessageHelper.GetReactionUsersAsync(this, emote, limit, Discord, options); | |||||
public Task PinAsync(RequestOptions options = null) | public Task PinAsync(RequestOptions options = null) | ||||
@@ -130,8 +130,8 @@ namespace Discord.WebSocket | |||||
=> MessageHelper.RemoveReactionAsync(this, user, emote, Discord, options); | => MessageHelper.RemoveReactionAsync(this, user, emote, Discord, options); | ||||
public Task RemoveAllReactionsAsync(RequestOptions options = null) | public Task RemoveAllReactionsAsync(RequestOptions options = null) | ||||
=> MessageHelper.RemoveAllReactionsAsync(this, Discord, options); | => MessageHelper.RemoveAllReactionsAsync(this, Discord, options); | ||||
public Task<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emote, int limit = 100, ulong? afterUserId = null, RequestOptions options = null) | |||||
=> MessageHelper.GetReactionUsersAsync(this, emote, x => { x.Limit = limit; x.AfterUserId = afterUserId ?? Optional.Create<ulong>(); }, Discord, options); | |||||
public IAsyncEnumerable<IReadOnlyCollection<IUser>> GetReactionUsersAsync(IEmote emote, int limit, RequestOptions options = null) | |||||
=> MessageHelper.GetReactionUsersAsync(this, emote, limit, Discord, options); | |||||
public Task PinAsync(RequestOptions options = null) | public Task PinAsync(RequestOptions options = null) | ||||
=> MessageHelper.PinAsync(this, Discord, options); | => MessageHelper.PinAsync(this, Discord, options); | ||||