Skip to content

Commit bbe9330

Browse files
authored
feat: Add support for export/users endpoint that allows for scheduling an async users exports task (#159)
* feat: Add support for `export/users` endpoint that allows for scheduling an async users exports task * Add docs code example * split code example * Rename code examples container
1 parent a9327af commit bbe9330

File tree

4 files changed

+93
-3
lines changed

4 files changed

+93
-3
lines changed
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using StreamChat.Clients;
2+
using StreamChat.Models;
3+
4+
namespace DocsExamples;
5+
6+
/// <summary>
7+
/// Code examples for <see href="https://getstream.io/chat/docs/dotnet-csharp/exporting_channels/"/>
8+
/// </summary>
9+
internal class ExportingChannels
10+
{
11+
private readonly IUserClient _userClient;
12+
private readonly ITaskClient _taskClient;
13+
14+
public ExportingChannels()
15+
{
16+
var factory = new StreamClientFactory("{{ api_key }}", "{{ api_secret }}");
17+
_userClient = factory.GetUserClient();
18+
_taskClient = factory.GetTaskClient();
19+
}
20+
21+
public async Task ExportUsersAsync()
22+
{
23+
var exportResponse = await _userClient.ExportUsersAsync(new[] { "user-id-1", "user-id-2" });
24+
var taskId = exportResponse.TaskId;
25+
}
26+
27+
public async Task RetrievingTaskStatusAsync()
28+
{
29+
var taskId = string.Empty;
30+
31+
// ITaskClient can provide the status of the export operation
32+
var taskStatus = await _taskClient.GetTaskStatusAsync(taskId);
33+
if (taskStatus.Status == AsyncTaskStatus.Completed)
34+
{
35+
// The export operation is completed
36+
// Result object contains the export file URL
37+
var exportedFileUrl = taskStatus.Result.Values.First().ToString();
38+
}
39+
}
40+
}

src/Clients/IUserClient.cs

+9-1
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,19 @@ public interface IUserClient
150150
Task<GenericUserResponse> ReactivateAsync(string id, bool restoreMessages = false, string name = null, string createdById = null);
151151

152152
/// <summary>
153-
/// Exports a user and returns an object containing all of it's data.
153+
/// Exports a user and returns an object containing all of its data.
154154
/// </summary>
155155
/// <remarks>https://getstream.io/chat/docs/dotnet-csharp/update_users/?language=csharp#exporting-users</remarks>
156156
Task<ExportedUser> ExportAsync(string userId);
157157

158+
/// <summary>
159+
/// Schedules user export task for a list of users
160+
/// </summary>
161+
/// <param name="userIds">user IDs to export</param>
162+
/// <returns>returns task ID that you can use to get export status (see <see cref="ITaskClient.GetTaskStatusAsync"/>)</returns>
163+
/// <remarks>https://getstream.io/chat/docs/dotnet-csharp/exporting_users/?language=csharp</remarks>
164+
Task<GenericTaskIdResponse> ExportUsersAsync(IEnumerable<string> userIds);
165+
158166
/// <summary>
159167
/// <para>Shadow bans a user.</para>
160168
/// When a user is shadow banned, they will still be allowed to post messages,

src/Clients/UserClient.cs

+9
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,15 @@ public async Task<ExportedUser> ExportAsync(string userId)
109109
HttpMethod.GET,
110110
HttpStatusCode.OK);
111111

112+
public async Task<GenericTaskIdResponse> ExportUsersAsync(IEnumerable<string> userIds)
113+
=> await ExecuteRequestAsync<GenericTaskIdResponse>("export/users",
114+
HttpMethod.POST,
115+
HttpStatusCode.Created,
116+
body: new
117+
{
118+
user_ids = userIds,
119+
});
120+
112121
public async Task<ApiResponse> ShadowBanAsync(ShadowBanRequest shadowBanRequest)
113122
=> await BanAsync(shadowBanRequest.ToBanRequest());
114123

tests/UserClientTests.cs

+35-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Net.Http;
35
using System.Text;
46
using System.Threading.Tasks;
57
using FluentAssertions;
68
using Newtonsoft.Json.Linq;
79
using NUnit.Framework;
8-
using StreamChat;
10+
using StreamChat.Clients;
911
using StreamChat.Exceptions;
1012
using StreamChat.Models;
1113

@@ -344,7 +346,7 @@ public async Task TestManyRevokeTokenAsync()
344346
}
345347

346348
[Test]
347-
public async Task TestQueryBannedUsers()
349+
public async Task TestQueryBannedUsersAsync()
348350
{
349351
await _userClient.BanAsync(new BanRequest
350352
{
@@ -364,5 +366,36 @@ await _userClient.BanAsync(new BanRequest
364366

365367
resp.Bans.Should().NotBeEmpty();
366368
}
369+
370+
[Test]
371+
public async Task TestExportUsersAsync()
372+
{
373+
var resp = await _userClient.ExportUsersAsync(new[] { _user1.Id, _user2.Id });
374+
375+
resp.TaskId.Should().NotBeNullOrEmpty();
376+
377+
AsyncTaskStatusResponse status = null;
378+
await WaitForAsync(async () =>
379+
{
380+
status = await _taskClient.GetTaskStatusAsync(resp.TaskId);
381+
382+
return status.Status == AsyncTaskStatus.Completed;
383+
}, timeout: 10000);
384+
385+
status.Should().NotBeNull();
386+
status.Status.Should().Be(AsyncTaskStatus.Completed);
387+
status.CreatedAt.Should().NotBeNull();
388+
status.Result.Should().NotBeNullOrEmpty();
389+
var exportUrl = status.Result.Values.First().ToString();
390+
exportUrl.Should().Contain("exports/users");
391+
392+
using var client = new HttpClient();
393+
using var response = await client.GetAsync(exportUrl);
394+
response.EnsureSuccessStatusCode();
395+
396+
var exportFile = await response.Content.ReadAsStringAsync();
397+
exportFile.Should().Contain(_user1.Id);
398+
exportFile.Should().Contain(_user2.Id);
399+
}
367400
}
368401
}

0 commit comments

Comments
 (0)