Support filtering audit log entries by after id (#2620)

Adds support for filtering audit log entires with GetAuditLogsAsync. Adds the ability to specify an afterId as specified on [Discord developers docs](https://discord.com/developers/docs/resources/audit-log#get-guild-audit-log).
This commit is contained in:
Alexander Elo
2023-03-31 14:21:27 +03:00
committed by GitHub
parent 4b4b6078b3
commit 529fe3d969
6 changed files with 27 additions and 16 deletions

View File

@@ -429,7 +429,7 @@ namespace Discord
/// </summary>
/// <remarks>
/// <note type="important">
/// The returned collection is an asynchronous enumerable object; one must call
/// The returned collection is an asynchronous enumerable object; one must call
/// <see cref="AsyncEnumerableExtensions.FlattenAsync{T}"/> to access the individual messages as a
/// collection.
/// </note>
@@ -449,7 +449,7 @@ namespace Discord
/// </summary>
/// <remarks>
/// <note type="important">
/// The returned collection is an asynchronous enumerable object; one must call
/// The returned collection is an asynchronous enumerable object; one must call
/// <see cref="AsyncEnumerableExtensions.FlattenAsync{T}"/> to access the individual messages as a
/// collection.
/// </note>
@@ -471,7 +471,7 @@ namespace Discord
/// </summary>
/// <remarks>
/// <note type="important">
/// The returned collection is an asynchronous enumerable object; one must call
/// The returned collection is an asynchronous enumerable object; one must call
/// <see cref="AsyncEnumerableExtensions.FlattenAsync{T}"/> to access the individual messages as a
/// collection.
/// </note>
@@ -1003,13 +1003,14 @@ namespace Discord
/// <param name="beforeId">The audit log entry ID to get entries before.</param>
/// <param name="actionType">The type of actions to filter.</param>
/// <param name="userId">The user ID to filter entries for.</param>
/// <param name="afterId">The audit log entry ID to get entries after.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection
/// of the requested audit log entries.
/// </returns>
Task<IReadOnlyCollection<IAuditLogEntry>> GetAuditLogsAsync(int limit = DiscordConfig.MaxAuditLogEntriesPerBatch,
CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null, ulong? beforeId = null, ulong? userId = null,
ActionType? actionType = null);
ActionType? actionType = null, ulong? afterId = null);
/// <summary>
/// Gets a webhook found within this guild.

View File

@@ -4,6 +4,7 @@ namespace Discord.API.Rest
{
public Optional<int> Limit { get; set; }
public Optional<ulong> BeforeEntryId { get; set; }
public Optional<ulong> AfterEntryId { get; set; }
public Optional<ulong> UserId { get; set; }
public Optional<int> ActionType { get; set; }
}

View File

@@ -2331,6 +2331,11 @@ namespace Discord.API
queryArgs.Append("&action_type=")
.Append(args.ActionType.Value);
}
if (args.AfterEntryId.IsSpecified)
{
queryArgs.Append("&after=")
.Append(args.AfterEntryId);
}
// Still use string interpolation for the query w/o params, as this is necessary for CreateBucketId
endpoint = () => $"guilds/{guildId}/audit-logs?limit={limit}{queryArgs.ToString()}";

View File

@@ -611,7 +611,7 @@ namespace Discord.Rest
#region Audit logs
public static IAsyncEnumerable<IReadOnlyCollection<RestAuditLogEntry>> GetAuditLogsAsync(IGuild guild, BaseDiscordClient client,
ulong? from, int? limit, RequestOptions options, ulong? userId = null, ActionType? actionType = null)
ulong? from, int? limit, RequestOptions options, ulong? userId = null, ActionType? actionType = null, ulong? afterId = null)
{
return new PagedAsyncEnumerable<RestAuditLogEntry>(
DiscordConfig.MaxAuditLogEntriesPerBatch,
@@ -627,6 +627,8 @@ namespace Discord.Rest
args.UserId = userId.Value;
if (actionType.HasValue)
args.ActionType = (int)actionType.Value;
if (afterId.HasValue)
args.AfterEntryId = afterId.Value;
var model = await client.ApiClient.GetAuditLogsAsync(guild.Id, args, options);
return model.Entries.Select((x) => RestAuditLogEntry.Create(client, model, x)).ToImmutableArray();
},
@@ -1081,7 +1083,7 @@ namespace Discord.Rest
throw new ArgumentException("Name of the rule must not be empty", paramName: nameof(args.Name));
Preconditions.AtLeast(1, args.Actions.GetValueOrDefault(Array.Empty<AutoModRuleActionProperties>()).Length, nameof(args.Actions), "Auto moderation rule must have at least 1 action");
if (args.RegexPatterns.IsSpecified)
{
if (args.TriggerType.Value is not AutoModTriggerType.Keyword)
@@ -1122,10 +1124,10 @@ namespace Discord.Rest
throw new ArgumentException(message: $"Allow list entry length must be less than or equal to {AutoModRuleProperties.MaxAllowListEntryLength}.", paramName: nameof(args.AllowList));
}
if (args.TriggerType.Value is not AutoModTriggerType.KeywordPreset && args.Presets.IsSpecified)
throw new ArgumentException(message: $"Keyword presets scan only be used with 'KeywordPreset' trigger type.", paramName: nameof(args.Presets));
if (args.MentionLimit.IsSpecified)
{
if (args.TriggerType.Value is AutoModTriggerType.MentionSpam)

View File

@@ -914,12 +914,13 @@ namespace Discord.Rest
/// <param name="beforeId">The audit log entry ID to get entries before.</param>
/// <param name="actionType">The type of actions to filter.</param>
/// <param name="userId">The user ID to filter entries for.</param>
/// <param name="afterId">The audit log entry ID to get entries after.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection
/// of the requested audit log entries.
/// </returns>
public IAsyncEnumerable<IReadOnlyCollection<RestAuditLogEntry>> GetAuditLogsAsync(int limit, RequestOptions options = null, ulong? beforeId = null, ulong? userId = null, ActionType? actionType = null)
=> GuildHelper.GetAuditLogsAsync(this, Discord, beforeId, limit, options, userId: userId, actionType: actionType);
public IAsyncEnumerable<IReadOnlyCollection<RestAuditLogEntry>> GetAuditLogsAsync(int limit, RequestOptions options = null, ulong? beforeId = null, ulong? userId = null, ActionType? actionType = null, ulong? afterId = null)
=> GuildHelper.GetAuditLogsAsync(this, Discord, beforeId, limit, options, userId: userId, actionType: actionType, afterId: afterId);
#endregion
#region Webhooks
@@ -1508,10 +1509,10 @@ namespace Discord.Rest
}
async Task<IReadOnlyCollection<IAuditLogEntry>> IGuild.GetAuditLogsAsync(int limit, CacheMode cacheMode, RequestOptions options,
ulong? beforeId, ulong? userId, ActionType? actionType)
ulong? beforeId, ulong? userId, ActionType? actionType, ulong? afterId)
{
if (cacheMode == CacheMode.AllowDownload)
return (await GetAuditLogsAsync(limit, options, beforeId: beforeId, userId: userId, actionType: actionType).FlattenAsync().ConfigureAwait(false)).ToImmutableArray();
return (await GetAuditLogsAsync(limit, options, beforeId: beforeId, userId: userId, actionType: actionType, afterId: afterId).FlattenAsync().ConfigureAwait(false)).ToImmutableArray();
else
return ImmutableArray.Create<IAuditLogEntry>();
}

View File

@@ -1397,12 +1397,13 @@ namespace Discord.WebSocket
/// <param name="beforeId">The audit log entry ID to filter entries before.</param>
/// <param name="actionType">The type of actions to filter.</param>
/// <param name="userId">The user ID to filter entries for.</param>
/// <param name="afterId">The audit log entry ID to filter entries after.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection
/// of the requested audit log entries.
/// </returns>
public IAsyncEnumerable<IReadOnlyCollection<RestAuditLogEntry>> GetAuditLogsAsync(int limit, RequestOptions options = null, ulong? beforeId = null, ulong? userId = null, ActionType? actionType = null)
=> GuildHelper.GetAuditLogsAsync(this, Discord, beforeId, limit, options, userId: userId, actionType: actionType);
public IAsyncEnumerable<IReadOnlyCollection<RestAuditLogEntry>> GetAuditLogsAsync(int limit, RequestOptions options = null, ulong? beforeId = null, ulong? userId = null, ActionType? actionType = null, ulong? afterId = null)
=> GuildHelper.GetAuditLogsAsync(this, Discord, beforeId, limit, options, userId: userId, actionType: actionType, afterId: afterId);
#endregion
#region Webhooks
@@ -2093,10 +2094,10 @@ namespace Discord.WebSocket
/// <inheritdoc />
async Task<IReadOnlyCollection<IAuditLogEntry>> IGuild.GetAuditLogsAsync(int limit, CacheMode cacheMode, RequestOptions options,
ulong? beforeId, ulong? userId, ActionType? actionType)
ulong? beforeId, ulong? userId, ActionType? actionType, ulong? afterId)
{
if (cacheMode == CacheMode.AllowDownload)
return (await GetAuditLogsAsync(limit, options, beforeId: beforeId, userId: userId, actionType: actionType).FlattenAsync().ConfigureAwait(false)).ToImmutableArray();
return (await GetAuditLogsAsync(limit, options, beforeId: beforeId, userId: userId, actionType: actionType, afterId: afterId).FlattenAsync().ConfigureAwait(false)).ToImmutableArray();
else
return ImmutableArray.Create<IAuditLogEntry>();
}