Skip to content

Commit e0b712f

Browse files
LulalabyCopilot
andauthored
feat!: add support for invite target user allowlists and job status (#756)
* feat: add support for invite target user allowlists and job status Introduces methods and endpoints to manage allowlists of users who can accept invites, including CSV-based and user ID-based updates. Adds the ability to query the processing status of invite target user jobs, updates the invite creation API to support role grants and target user restrictions, and implements supporting types and utilities for these features. * Rename Values to SelectedValues in checkbox group Renamed the 'Values' property to 'SelectedValues' in DiscordCheckboxGroupComponent to improve clarity and better reflect its purpose. * refactor: address code review feedback on invite target users feature (#757) * Initial plan * docs: improve documentation and code quality for invite target users Co-Authored-By: copilot-swe-agent[bot] <[email protected]> Co-authored-by: Lulalaby <[email protected]> * fix: prevent memory leak by not resetting internally-created MemoryStream Co-Authored-By: copilot-swe-agent[bot] <[email protected]> Co-authored-by: Lulalaby <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: Lulalaby <[email protected]> * Dispose targetUsersCsv streams after use Added try-catch blocks to dispose the targetUsersCsv streams in CreateChannelInviteAsync and UpdateInviteTargetUsersAsync methods to ensure proper resource cleanup and prevent potential memory leaks. --------- Co-authored-by: Copilot <[email protected]>
1 parent 9cf8174 commit e0b712f

File tree

10 files changed

+410
-10
lines changed

10 files changed

+410
-10
lines changed

DisCatSharp/Clients/DiscordClient.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,67 @@ public bool TryGetInviteByCode(string code, [NotNullWhen(true)] out DiscordInvit
11111111
}
11121112
}
11131113

1114+
/// <summary>
1115+
/// Gets the target users allowed to accept an invite.
1116+
/// </summary>
1117+
/// <param name="inviteCode">The invite code.</param>
1118+
/// <returns>An allowlist of user ids.</returns>
1119+
/// <exception cref="NotFoundException">Thrown when the invite does not exist.</exception>
1120+
/// <exception cref="BadRequestException">Thrown when an invalid parameter was provided.</exception>
1121+
/// <exception cref="ServerErrorException">Thrown when Discord is unable to process the request.</exception>
1122+
public Task<IReadOnlyList<ulong>> GetInviteTargetUsersAsync(string inviteCode)
1123+
=> this.ApiClient.GetInviteTargetUsersAsync(inviteCode);
1124+
1125+
/// <summary>
1126+
/// Updates the target users allowed to accept an invite using a CSV stream.
1127+
/// </summary>
1128+
/// <param name="inviteCode">The invite code.</param>
1129+
/// <param name="targetUsersCsv">
1130+
/// CSV stream containing a single <c>Users</c> column. The CSV must have a header row where the first
1131+
/// (and only) column header is <c>Users</c>, and each subsequent line must contain exactly one user ID.
1132+
/// </param>
1133+
/// <param name="reason">The audit log reason.</param>
1134+
/// <exception cref="NotFoundException">Thrown when the invite does not exist.</exception>
1135+
/// <exception cref="BadRequestException">Thrown when an invalid parameter was provided.</exception>
1136+
/// <exception cref="ServerErrorException">Thrown when Discord is unable to process the request.</exception>
1137+
public Task UpdateInviteTargetUsersAsync(string inviteCode, Stream targetUsersCsv, string reason = null)
1138+
=> this.ApiClient.UpdateInviteTargetUsersAsync(inviteCode, targetUsersCsv, null, null, reason);
1139+
1140+
/// <summary>
1141+
/// Updates the target users allowed to accept an invite using user ids.
1142+
/// </summary>
1143+
/// <param name="inviteCode">The invite code.</param>
1144+
/// <param name="targetUserIds">User ids allowed to accept the invite.</param>
1145+
/// <param name="reason">The audit log reason.</param>
1146+
/// <exception cref="NotFoundException">Thrown when the invite does not exist.</exception>
1147+
/// <exception cref="BadRequestException">Thrown when an invalid parameter was provided.</exception>
1148+
/// <exception cref="ServerErrorException">Thrown when Discord is unable to process the request.</exception>
1149+
public Task UpdateInviteTargetUsersAsync(string inviteCode, IEnumerable<ulong> targetUserIds, string reason = null)
1150+
=> this.ApiClient.UpdateInviteTargetUsersAsync(inviteCode, null, targetUserIds, null, reason);
1151+
1152+
/// <summary>
1153+
/// Updates the target users allowed to accept an invite using user objects.
1154+
/// </summary>
1155+
/// <param name="inviteCode">The invite code.</param>
1156+
/// <param name="targetUsers">Users allowed to accept the invite.</param>
1157+
/// <param name="reason">The audit log reason.</param>
1158+
/// <exception cref="NotFoundException">Thrown when the invite does not exist.</exception>
1159+
/// <exception cref="BadRequestException">Thrown when an invalid parameter was provided.</exception>
1160+
/// <exception cref="ServerErrorException">Thrown when Discord is unable to process the request.</exception>
1161+
public Task UpdateInviteTargetUsersAsync(string inviteCode, IEnumerable<DiscordUser> targetUsers, string reason = null)
1162+
=> this.ApiClient.UpdateInviteTargetUsersAsync(inviteCode, null, null, targetUsers, reason);
1163+
1164+
/// <summary>
1165+
/// Gets the invite target users job status.
1166+
/// </summary>
1167+
/// <param name="inviteCode">The invite code.</param>
1168+
/// <returns>The job status.</returns>
1169+
/// <exception cref="NotFoundException">Thrown when the invite does not exist.</exception>
1170+
/// <exception cref="BadRequestException">Thrown when an invalid parameter was provided.</exception>
1171+
/// <exception cref="ServerErrorException">Thrown when Discord is unable to process the request.</exception>
1172+
public Task<DiscordInviteTargetUsersJobStatus> GetInviteTargetUsersJobStatusAsync(string inviteCode)
1173+
=> this.ApiClient.GetInviteTargetUsersJobStatusAsync(inviteCode);
1174+
11141175
/// <summary>
11151176
/// Gets a list of user connections.
11161177
/// </summary>

DisCatSharp/Entities/Channel/DiscordChannel.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,15 +1121,25 @@ public Task<IReadOnlyList<DiscordInvite>> GetInvitesAsync() =>
11211121
/// <param name="targetApplicationId">The target activity ID. Defaults to null.</param>
11221122
/// <param name="targetUser">The target user id. Defaults to null.</param>
11231123
/// <param name="reason">The audit log reason.</param>
1124+
/// <param name="roleIds">Role ids to grant when the invite is accepted.</param>
1125+
/// <param name="targetUserIds">Allowed target user ids for the invite.</param>
1126+
/// <param name="targetUsers">Allowed target users for the invite.</param>
1127+
/// <param name="targetUsersCsv">Optional CSV stream defining allowed users.</param>
11241128
/// <exception cref="UnauthorizedException">
11251129
/// Thrown when the client does not have the
11261130
/// <see cref="Permissions.CreateInstantInvite" /> permission.
11271131
/// </exception>
11281132
/// <exception cref="NotFoundException">Thrown when the channel does not exist.</exception>
11291133
/// <exception cref="BadRequestException">Thrown when an invalid parameter was provided.</exception>
11301134
/// <exception cref="ServerErrorException">Thrown when Discord is unable to process the request.</exception>
1131-
public Task<DiscordInvite> CreateInviteAsync(int maxAge = 86400, int maxUses = 0, bool temporary = false, bool unique = false, TargetType? targetType = null, ulong? targetApplicationId = null, ulong? targetUser = null, string reason = null)
1132-
=> this.Discord.ApiClient.CreateChannelInviteAsync(this.Id, maxAge, maxUses, targetType, targetApplicationId, targetUser, temporary, unique, reason);
1135+
/// <exception cref="ArgumentException">Thrown when the provided stream is not readable.</exception>
1136+
public Task<DiscordInvite> CreateInviteAsync(int maxAge = 86400, int maxUses = 0, bool temporary = false, bool unique = false, TargetType? targetType = null, ulong? targetApplicationId = null, ulong? targetUser = null, string reason = null, IEnumerable<ulong>? roleIds = null, IEnumerable<ulong>? targetUserIds = null, IEnumerable<DiscordUser>? targetUsers = null, Stream? targetUsersCsv = null)
1137+
{
1138+
if (targetUsersCsv is not null && !targetUsersCsv.CanRead)
1139+
throw new ArgumentException("The provided stream must be readable.", nameof(targetUsersCsv));
1140+
1141+
return this.Discord.ApiClient.CreateChannelInviteAsync(this.Id, maxAge, maxUses, targetType, targetApplicationId, targetUser, temporary, unique, reason, roleIds, targetUserIds, targetUsers, targetUsersCsv);
1142+
}
11331143

11341144
#region Voice Channel
11351145

DisCatSharp/Entities/Components/V2Components/DiscordCheckboxGroupComponent.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public DiscordCheckboxGroupComponent(IEnumerable<DiscordCheckboxGroupComponentOp
9090
/// The submitted values. Present on modal submit interactions.
9191
/// </summary>
9292
[JsonProperty("values", NullValueHandling = NullValueHandling.Ignore)]
93-
public string[]? Values { get; internal set; }
93+
public string[]? SelectedValues { get; internal set; }
9494

9595
/// <summary>
9696
/// Assigns a unique id to this component.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
3+
using DisCatSharp.Enums;
4+
5+
using Newtonsoft.Json;
6+
7+
namespace DisCatSharp.Entities;
8+
9+
/// <summary>
10+
/// Represents the processing status for invite target users.
11+
/// </summary>
12+
public sealed class DiscordInviteTargetUsersJobStatus : ObservableApiObject
13+
{
14+
/// <summary>
15+
/// Gets the status of the job.
16+
/// </summary>
17+
[JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)]
18+
public InviteTargetUsersJobStatus Status { get; internal set; }
19+
20+
/// <summary>
21+
/// Gets the total number of users in the job.
22+
/// </summary>
23+
[JsonProperty("total_users", NullValueHandling = NullValueHandling.Ignore)]
24+
public int TotalUsers { get; internal set; }
25+
26+
/// <summary>
27+
/// Gets the processed users count.
28+
/// </summary>
29+
[JsonProperty("processed_users", NullValueHandling = NullValueHandling.Ignore)]
30+
public int ProcessedUsers { get; internal set; }
31+
32+
/// <summary>
33+
/// Gets when the job was created.
34+
/// </summary>
35+
[JsonProperty("created_at", NullValueHandling = NullValueHandling.Ignore)]
36+
public DateTimeOffset CreatedAt { get; internal set; }
37+
38+
/// <summary>
39+
/// Gets when the job completed, if applicable.
40+
/// </summary>
41+
[JsonProperty("completed_at", NullValueHandling = NullValueHandling.Ignore)]
42+
public DateTimeOffset? CompletedAt { get; internal set; }
43+
44+
/// <summary>
45+
/// Gets the error message if the job failed.
46+
/// </summary>
47+
[JsonProperty("error_message", NullValueHandling = NullValueHandling.Ignore)]
48+
public string? ErrorMessage { get; internal set; }
49+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
namespace DisCatSharp.Enums;
2+
3+
/// <summary>
4+
/// Represents the processing status for invite target users jobs.
5+
/// </summary>
6+
public enum InviteTargetUsersJobStatus
7+
{
8+
/// <summary>
9+
/// The status is unspecified.
10+
/// </summary>
11+
Unspecified = 0,
12+
13+
/// <summary>
14+
/// The target users job is processing.
15+
/// </summary>
16+
Processing = 1,
17+
18+
/// <summary>
19+
/// The target users job completed successfully.
20+
/// </summary>
21+
Completed = 2,
22+
23+
/// <summary>
24+
/// The target users job failed.
25+
/// </summary>
26+
Failed = 3
27+
}

DisCatSharp/Net/Abstractions/Rest/RestChannelPayloads.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,12 @@ internal sealed class RestChannelInviteCreatePayload : ObservableApiObject
419419
/// </summary>
420420
[JsonProperty("unique", NullValueHandling = NullValueHandling.Ignore)]
421421
public bool Unique { get; set; }
422+
423+
/// <summary>
424+
/// Gets or sets the role ids to grant when the invite is accepted.
425+
/// </summary>
426+
[JsonProperty("role_ids", NullValueHandling = NullValueHandling.Ignore)]
427+
public IEnumerable<ulong>? RoleIds { get; set; }
422428
}
423429

424430
/// <summary>

0 commit comments

Comments
 (0)