From 03402cd4d243c0a30faede4768254fbd3b542491 Mon Sep 17 00:00:00 2001
From: Mihail Gribkov <61027276+Misha-133@users.noreply.github.com>
Date: Sat, 16 Mar 2024 01:22:23 +0300
Subject: [PATCH] [Feature] Bulk ban support (#2881)
---
.../Entities/Guilds/BulkBanResult.cs | 25 +++++++++++++++++++
.../Entities/Guilds/IGuild.cs | 11 ++++++++
.../API/Common/BulkBanResult.cs | 12 +++++++++
.../API/Rest/BulkBanParams.cs | 12 +++++++++
src/Discord.Net.Rest/DiscordRestApiClient.cs | 17 +++++++++++++
.../Entities/Guilds/GuildHelper.cs | 7 ++++++
.../Entities/Guilds/RestGuild.cs | 4 +++
.../Entities/Guilds/SocketGuild.cs | 4 +++
8 files changed, 92 insertions(+)
create mode 100644 src/Discord.Net.Core/Entities/Guilds/BulkBanResult.cs
create mode 100644 src/Discord.Net.Rest/API/Common/BulkBanResult.cs
create mode 100644 src/Discord.Net.Rest/API/Rest/BulkBanParams.cs
diff --git a/src/Discord.Net.Core/Entities/Guilds/BulkBanResult.cs b/src/Discord.Net.Core/Entities/Guilds/BulkBanResult.cs
new file mode 100644
index 00000000..8e702f0c
--- /dev/null
+++ b/src/Discord.Net.Core/Entities/Guilds/BulkBanResult.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+
+namespace Discord;
+
+///
+/// Represents a result of a bulk ban.
+///
+public readonly struct BulkBanResult
+{
+ ///
+ /// Gets the collection of user IDs that were successfully banned.
+ ///
+ public IReadOnlyCollection BannedUsers { get; }
+
+ ///
+ /// Gets the collection of user IDs that failed to be banned.
+ ///
+ public IReadOnlyCollection FailedUsers { get; }
+
+ internal BulkBanResult(IReadOnlyCollection bannedUsers, IReadOnlyCollection failedUsers)
+ {
+ BannedUsers = bannedUsers;
+ FailedUsers = failedUsers;
+ }
+}
diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs
index 143efd61..20bf3a7f 100644
--- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs
+++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs
@@ -1418,5 +1418,16 @@ namespace Discord
/// A task that represents the asynchronous creation operation. The task result contains the modified .
///
Task ModifyIncidentActionsAsync(Action props, RequestOptions options = null);
+
+ ///
+ /// Executes a bulk ban on the specified users.
+ ///
+ /// A collection of user ids to ban.
+ /// The number of seconds to delete messages for. Max 604800.
+ /// The options to be used when sending the request.
+ ///
+ /// A task that represents the asynchronous creation operation. The task result contains a .
+ ///
+ Task BulkBanAsync(IEnumerable userIds, int? deleteMessageSeconds = null, RequestOptions options = null);
}
}
diff --git a/src/Discord.Net.Rest/API/Common/BulkBanResult.cs b/src/Discord.Net.Rest/API/Common/BulkBanResult.cs
new file mode 100644
index 00000000..51e387e7
--- /dev/null
+++ b/src/Discord.Net.Rest/API/Common/BulkBanResult.cs
@@ -0,0 +1,12 @@
+using Newtonsoft.Json;
+
+namespace Discord.API;
+
+internal class BulkBanResult
+{
+ [JsonProperty("banned_users")]
+ public ulong[] BannedUsers { get; set; }
+
+ [JsonProperty("failed_users")]
+ public ulong[] FailedUsers { get; set; }
+}
diff --git a/src/Discord.Net.Rest/API/Rest/BulkBanParams.cs b/src/Discord.Net.Rest/API/Rest/BulkBanParams.cs
new file mode 100644
index 00000000..e7c03378
--- /dev/null
+++ b/src/Discord.Net.Rest/API/Rest/BulkBanParams.cs
@@ -0,0 +1,12 @@
+using Newtonsoft.Json;
+
+namespace Discord.API.Rest;
+
+internal class BulkBanParams
+{
+ [JsonProperty("user_ids")]
+ public ulong[] UserIds { get; set; }
+
+ [JsonProperty("delete_message_seconds")]
+ public Optional DeleteMessageSeconds { get; set; }
+}
diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs
index c5f13314..4778f3ed 100644
--- a/src/Discord.Net.Rest/DiscordRestApiClient.cs
+++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs
@@ -1771,6 +1771,23 @@ namespace Discord.API
var ids = new BucketIds(guildId: guildId);
return SendAsync("DELETE", () => $"guilds/{guildId}/bans/{userId}", ids, options: options);
}
+
+ public Task BulkBanAsync(ulong guildId, ulong[] userIds, int? deleteMessagesSeconds = null, RequestOptions options = null)
+ {
+ Preconditions.NotEqual(userIds.Length, 0, nameof(userIds));
+ Preconditions.AtMost(userIds.Length, 200, nameof(userIds));
+ Preconditions.AtMost(deleteMessagesSeconds ?? 0, 604800, nameof(deleteMessagesSeconds));
+
+ options = RequestOptions.CreateOrClone(options);
+
+ var data = new BulkBanParams
+ {
+ DeleteMessageSeconds = deleteMessagesSeconds ?? Optional.Unspecified,
+ UserIds = userIds
+ };
+
+ return SendJsonAsync("POST", () => $"guilds/{guildId}/bulk-ban", data, new BucketIds(guildId), options: options);
+ }
#endregion
#region Guild Widget
diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
index 407c52f8..d05352a0 100644
--- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
+++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
@@ -244,6 +244,13 @@ namespace Discord.Rest
public static Task RemoveBanAsync(IGuild guild, BaseDiscordClient client, ulong userId, RequestOptions options)
=> client.ApiClient.RemoveGuildBanAsync(guild.Id, userId, options);
+
+ public static async Task BulkBanAsync(IGuild guild, BaseDiscordClient client, ulong[] userIds, int? deleteMessageSeconds, RequestOptions options)
+ {
+ var model = await client.ApiClient.BulkBanAsync(guild.Id, userIds, deleteMessageSeconds, options);
+ return new(model.BannedUsers?.ToImmutableArray() ?? ImmutableArray.Empty,
+ model.FailedUsers?.ToImmutableArray() ?? ImmutableArray.Empty);
+ }
#endregion
#region Channels
diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
index 86dcafde..3ae3d17d 100644
--- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
+++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
@@ -401,6 +401,10 @@ namespace Discord.Rest
///
public Task RemoveBanAsync(ulong userId, RequestOptions options = null)
=> GuildHelper.RemoveBanAsync(this, Discord, userId, options);
+
+ ///
+ public Task BulkBanAsync(IEnumerable userIds, int? deleteMessageSeconds = null, RequestOptions options = null)
+ => GuildHelper.BulkBanAsync(this, Discord, userIds.ToArray(), deleteMessageSeconds, options);
#endregion
#region Channels
diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
index 463ee7cd..b2b1e661 100644
--- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
+++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
@@ -722,6 +722,10 @@ namespace Discord.WebSocket
///
public Task RemoveBanAsync(ulong userId, RequestOptions options = null)
=> GuildHelper.RemoveBanAsync(this, Discord, userId, options);
+
+ ///
+ public Task BulkBanAsync(IEnumerable userIds, int? deleteMessageSeconds = null, RequestOptions options = null)
+ => GuildHelper.BulkBanAsync(this, Discord, userIds.ToArray(), deleteMessageSeconds, options);
#endregion
#region Channels