Skip to content

Commit b44fc6d

Browse files
authored
Add community invites (#297)
* Add TargetUsers and RoleIds to InviteProperties * Add more invite endpoints * Move InviteTargetUsersProperties to a separate file and fix its logic * Dispose stream and fix indentation * Add tests for InviteTargetUsersProperties.FromEnumerable * Rename a parameter of UpdateInviteTargetUsersAsync * Add a test for GetInviteTargetUsersAsync * Dispose a response stream in test * Add Invite.Roles property * Fix the names of invite RestClient methods * Fix filename for RestInvite * Update invite receive objects * Add a missing flags attribute * Do not rent a buffer for UserIdsStream * Only allow for sending InviteTargetUsersProperties once
1 parent cbfe16c commit b44fc6d

18 files changed

Lines changed: 520 additions & 25 deletions

NetCord.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
<File Path="Tests/Directory.Build.targets" />
8585
<Project Path="Tests/ColorTest/ColorTest.csproj" />
8686
<Project Path="Tests/MentionTest/MentionTest.csproj" />
87+
<Project Path="Tests/NetCord.Rest.Tests/NetCord.Rest.Tests.csproj" />
8788
<Project Path="Tests/NetCord.Test.Hosting.AspNetCore/NetCord.Test.Hosting.AspNetCore.csproj" />
8889
<Project Path="Tests/NetCord.Test.Hosting/NetCord.Test.Hosting.csproj" />
8990
<Project Path="Tests/NetCord.Test.Sharded.Hosting/NetCord.Test.Sharded.Hosting.csproj" />

NetCord/Gateway/Invite.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ public Invite(JsonModels.JsonInvite jsonModel, RestClient client)
5050

5151
public int Uses => _jsonModel.Uses;
5252

53+
public DateTimeOffset? ExpiresAt => _jsonModel.ExpiresAt;
54+
55+
public IReadOnlyList<ulong>? RoleIds => _jsonModel.RoleIds;
56+
5357
ulong? IInvite.ChannelId => ChannelId;
5458

5559
int? IInvite.MaxAge => MaxAge;

NetCord/Gateway/JsonModels/JsonInvite.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,10 @@ public class JsonInvite
4444

4545
[JsonPropertyName("uses")]
4646
public int Uses { get; set; }
47+
48+
[JsonPropertyName("expires_at")]
49+
public DateTimeOffset? ExpiresAt { get; set; }
50+
51+
[JsonPropertyName("role_ids")]
52+
public ulong[]? RoleIds { get; set; }
4753
}

NetCord/IInvite.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ public interface IInvite
1515
public bool? Temporary { get; }
1616
public int? Uses { get; }
1717
public DateTimeOffset? CreatedAt { get; }
18+
public DateTimeOffset? ExpiresAt { get; }
1819
}

NetCord/InviteFlags.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace NetCord;
2+
3+
[Flags]
4+
public enum InviteFlags
5+
{
6+
IsGuestInvite = 1 << 0,
7+
}

NetCord/Rest/InviteProperties.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace NetCord.Rest;
44

55
[GenerateMethodsForProperties]
6-
public partial class InviteProperties
6+
public partial class InviteProperties : IHttpSerializable
77
{
88
[JsonPropertyName("max_age")]
99
public int? MaxAge { get; set; }
@@ -25,4 +25,26 @@ public partial class InviteProperties
2525

2626
[JsonPropertyName("target_application_id")]
2727
public ulong? TargetApplicationId { get; set; }
28+
29+
[JsonIgnore]
30+
public InviteTargetUsersProperties? TargetUsers { get; set; }
31+
32+
[JsonPropertyName("role_ids")]
33+
public IEnumerable<ulong>? RoleIds { get; set; }
34+
35+
HttpContent IHttpSerializable.Serialize() => Serialize();
36+
37+
internal HttpContent Serialize()
38+
{
39+
JsonContent<InviteProperties> inviteContent = new(this, Serialization.Default.InviteProperties);
40+
41+
if (TargetUsers is not { } targetUsers)
42+
return inviteContent;
43+
44+
return new MultipartFormDataContent()
45+
{
46+
{ inviteContent, "payload_json" },
47+
{ targetUsers.Serialize(), "target_users_file", "target_users_file" }
48+
};
49+
}
2850
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using NetCord.Rest.JsonModels;
2+
3+
namespace NetCord.Rest;
4+
5+
public class InviteTargetUsersJobStatus(JsonInviteTargetUsersJobStatus jsonModel) : IJsonModel<JsonInviteTargetUsersJobStatus>
6+
{
7+
JsonInviteTargetUsersJobStatus IJsonModel<JsonInviteTargetUsersJobStatus>.JsonModel => jsonModel;
8+
9+
public InviteTargetUsersJobStatusCode Status => jsonModel.Status;
10+
11+
public int TotalUsers => jsonModel.TotalUsers;
12+
13+
public int ProcessedUsers => jsonModel.ProcessedUsers;
14+
15+
public DateTimeOffset CreatedAt => jsonModel.CreatedAt;
16+
17+
public DateTimeOffset? CompletedAt => jsonModel.CompletedAt;
18+
19+
public string? ErrorMessage => jsonModel.ErrorMessage;
20+
}
21+
22+
public enum InviteTargetUsersJobStatusCode
23+
{
24+
Unspecified = 0,
25+
Processing = 1,
26+
Completed = 2,
27+
Failed = 3,
28+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
using System.Buffers.Text;
2+
using System.Diagnostics.CodeAnalysis;
3+
4+
namespace NetCord.Rest;
5+
6+
[GenerateMethodsForProperties]
7+
public partial class InviteTargetUsersProperties : IHttpSerializable
8+
{
9+
private readonly Stream _stream;
10+
private byte _read;
11+
12+
private InviteTargetUsersProperties(Stream stream)
13+
{
14+
_stream = stream;
15+
}
16+
17+
public static InviteTargetUsersProperties FromStream(Stream stream) => new(stream);
18+
19+
public static InviteTargetUsersProperties FromEnumerable(IEnumerable<ulong> userIds) => new(new UserIdsStream(userIds));
20+
21+
HttpContent IHttpSerializable.Serialize() => Serialize();
22+
23+
internal HttpContent Serialize()
24+
{
25+
if (Interlocked.Exchange(ref _read, 1) is 1)
26+
ThrowAlreadySent();
27+
28+
return new StreamContent(_stream);
29+
}
30+
31+
[DoesNotReturn]
32+
private static void ThrowAlreadySent()
33+
{
34+
throw new InvalidOperationException("The invite target users have already been sent.");
35+
}
36+
37+
private sealed class UserIdsStream(IEnumerable<ulong> userIds) : Stream
38+
{
39+
private readonly IEnumerator<ulong> _enumerator = userIds.GetEnumerator();
40+
private readonly byte[] _buffer = new byte[22];
41+
private int _startPosition;
42+
private int _endPosition;
43+
44+
public override bool CanRead => true;
45+
46+
public override bool CanSeek => false;
47+
48+
public override bool CanWrite => false;
49+
50+
public override long Length => throw new NotSupportedException();
51+
52+
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
53+
54+
public override void Flush() => throw new NotSupportedException();
55+
56+
public override int Read(byte[] buffer, int offset, int count) => Read(new Span<byte>(buffer, offset, count));
57+
58+
public override int Read(Span<byte> buffer)
59+
{
60+
int totalWritten = 0;
61+
62+
if (_startPosition != _endPosition)
63+
{
64+
var bufferedLength = _endPosition - _startPosition;
65+
66+
var length = Math.Min(bufferedLength, buffer.Length);
67+
68+
_buffer.AsSpan(_startPosition, length).CopyTo(buffer);
69+
_startPosition += length;
70+
71+
if (length != bufferedLength)
72+
return length;
73+
74+
totalWritten += length;
75+
}
76+
77+
var newLine = "\r\n"u8;
78+
79+
while (_enumerator.MoveNext())
80+
{
81+
var userId = _enumerator.Current;
82+
if (!Utf8Formatter.TryFormat(userId, buffer[totalWritten..], out var written))
83+
{
84+
_ = Utf8Formatter.TryFormat(userId, _buffer, out var writtenToBuffer);
85+
86+
_buffer.AsSpan(0, _startPosition = written = buffer.Length - totalWritten).CopyTo(buffer[totalWritten..]);
87+
88+
totalWritten += written;
89+
90+
newLine.CopyTo(_buffer.AsSpan(writtenToBuffer));
91+
_endPosition = writtenToBuffer + newLine.Length;
92+
break;
93+
}
94+
95+
totalWritten += written;
96+
97+
if (!newLine.TryCopyTo(buffer[totalWritten..]))
98+
{
99+
var remaining = buffer.Length - totalWritten;
100+
if (remaining > 0)
101+
{
102+
newLine[..remaining].CopyTo(buffer[totalWritten..]);
103+
totalWritten += remaining;
104+
}
105+
106+
newLine[remaining..].CopyTo(_buffer);
107+
_startPosition = 0;
108+
_endPosition = newLine.Length - remaining;
109+
110+
break;
111+
}
112+
113+
totalWritten += newLine.Length;
114+
}
115+
116+
return totalWritten;
117+
}
118+
119+
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
120+
{
121+
return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
122+
}
123+
124+
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
125+
{
126+
return new(Read(buffer.Span));
127+
}
128+
129+
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
130+
public override void SetLength(long value) => throw new NotSupportedException();
131+
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
132+
133+
protected override void Dispose(bool disposing)
134+
{
135+
if (disposing)
136+
_enumerator.Dispose();
137+
}
138+
}
139+
}
140+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace NetCord.Rest.JsonModels;
4+
5+
public class JsonInviteTargetUsersJobStatus
6+
{
7+
[JsonPropertyName("status")]
8+
public InviteTargetUsersJobStatusCode Status { get; set; }
9+
10+
[JsonPropertyName("total_users")]
11+
public int TotalUsers { get; set; }
12+
13+
[JsonPropertyName("processed_users")]
14+
public int ProcessedUsers { get; set; }
15+
16+
[JsonPropertyName("created_at")]
17+
public DateTimeOffset CreatedAt { get; set; }
18+
19+
[JsonPropertyName("completed_at")]
20+
public DateTimeOffset? CompletedAt { get; set; }
21+
22+
[JsonPropertyName("error_message")]
23+
public string? ErrorMessage { get; set; }
24+
}

NetCord/Rest/JsonModels/JsonRestInvite.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,15 @@ public class JsonRestInvite
3939
[JsonPropertyName("expires_at")]
4040
public DateTimeOffset? ExpiresAt { get; set; }
4141

42-
[JsonPropertyName("stage_instance")]
43-
public JsonStageInstance? StageInstance { get; set; }
44-
4542
[JsonPropertyName("guild_scheduled_event")]
4643
public JsonGuildScheduledEvent? GuildScheduledEvent { get; set; }
4744

45+
[JsonPropertyName("flags")]
46+
public InviteFlags? Flags { get; set; }
47+
48+
[JsonPropertyName("roles")]
49+
public JsonRole[]? Roles { get; set; }
50+
4851
[JsonPropertyName("uses")]
4952
public int? Uses { get; set; }
5053

0 commit comments

Comments
 (0)