diff --git a/samples/DocsExamples/ExportingChannels.cs b/samples/DocsExamples/ExportingChannels.cs
new file mode 100644
index 0000000..74e831a
--- /dev/null
+++ b/samples/DocsExamples/ExportingChannels.cs
@@ -0,0 +1,40 @@
+using StreamChat.Clients;
+using StreamChat.Models;
+
+namespace DocsExamples;
+
+///
+/// Code examples for
+///
+internal class ExportingChannels
+{
+ private readonly IUserClient _userClient;
+ private readonly ITaskClient _taskClient;
+
+ public ExportingChannels()
+ {
+ var factory = new StreamClientFactory("{{ api_key }}", "{{ api_secret }}");
+ _userClient = factory.GetUserClient();
+ _taskClient = factory.GetTaskClient();
+ }
+
+ public async Task ExportUsersAsync()
+ {
+ var exportResponse = await _userClient.ExportUsersAsync(new[] { "user-id-1", "user-id-2" });
+ var taskId = exportResponse.TaskId;
+ }
+
+ public async Task RetrievingTaskStatusAsync()
+ {
+ var taskId = string.Empty;
+
+ // ITaskClient can provide the status of the export operation
+ var taskStatus = await _taskClient.GetTaskStatusAsync(taskId);
+ if (taskStatus.Status == AsyncTaskStatus.Completed)
+ {
+ // The export operation is completed
+ // Result object contains the export file URL
+ var exportedFileUrl = taskStatus.Result.Values.First().ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Clients/IUserClient.cs b/src/Clients/IUserClient.cs
index 8adba3e..13d4ad5 100644
--- a/src/Clients/IUserClient.cs
+++ b/src/Clients/IUserClient.cs
@@ -150,11 +150,19 @@ public interface IUserClient
Task ReactivateAsync(string id, bool restoreMessages = false, string name = null, string createdById = null);
///
- /// Exports a user and returns an object containing all of it's data.
+ /// Exports a user and returns an object containing all of its data.
///
/// https://getstream.io/chat/docs/dotnet-csharp/update_users/?language=csharp#exporting-users
Task ExportAsync(string userId);
+ ///
+ /// Schedules user export task for a list of users
+ ///
+ /// user IDs to export
+ /// returns task ID that you can use to get export status (see )
+ /// https://getstream.io/chat/docs/dotnet-csharp/exporting_users/?language=csharp
+ Task ExportUsersAsync(IEnumerable userIds);
+
///
/// Shadow bans a user.
/// When a user is shadow banned, they will still be allowed to post messages,
diff --git a/src/Clients/UserClient.cs b/src/Clients/UserClient.cs
index 78fab0e..bcca8e3 100644
--- a/src/Clients/UserClient.cs
+++ b/src/Clients/UserClient.cs
@@ -109,6 +109,15 @@ public async Task ExportAsync(string userId)
HttpMethod.GET,
HttpStatusCode.OK);
+ public async Task ExportUsersAsync(IEnumerable userIds)
+ => await ExecuteRequestAsync("export/users",
+ HttpMethod.POST,
+ HttpStatusCode.Created,
+ body: new
+ {
+ user_ids = userIds,
+ });
+
public async Task ShadowBanAsync(ShadowBanRequest shadowBanRequest)
=> await BanAsync(shadowBanRequest.ToBanRequest());
diff --git a/tests/UserClientTests.cs b/tests/UserClientTests.cs
index 4b1489c..7098a94 100644
--- a/tests/UserClientTests.cs
+++ b/tests/UserClientTests.cs
@@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using FluentAssertions;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
-using StreamChat;
+using StreamChat.Clients;
using StreamChat.Exceptions;
using StreamChat.Models;
@@ -344,7 +346,7 @@ public async Task TestManyRevokeTokenAsync()
}
[Test]
- public async Task TestQueryBannedUsers()
+ public async Task TestQueryBannedUsersAsync()
{
await _userClient.BanAsync(new BanRequest
{
@@ -364,5 +366,36 @@ await _userClient.BanAsync(new BanRequest
resp.Bans.Should().NotBeEmpty();
}
+
+ [Test]
+ public async Task TestExportUsersAsync()
+ {
+ var resp = await _userClient.ExportUsersAsync(new[] { _user1.Id, _user2.Id });
+
+ resp.TaskId.Should().NotBeNullOrEmpty();
+
+ AsyncTaskStatusResponse status = null;
+ await WaitForAsync(async () =>
+ {
+ status = await _taskClient.GetTaskStatusAsync(resp.TaskId);
+
+ return status.Status == AsyncTaskStatus.Completed;
+ }, timeout: 10000);
+
+ status.Should().NotBeNull();
+ status.Status.Should().Be(AsyncTaskStatus.Completed);
+ status.CreatedAt.Should().NotBeNull();
+ status.Result.Should().NotBeNullOrEmpty();
+ var exportUrl = status.Result.Values.First().ToString();
+ exportUrl.Should().Contain("exports/users");
+
+ using var client = new HttpClient();
+ using var response = await client.GetAsync(exportUrl);
+ response.EnsureSuccessStatusCode();
+
+ var exportFile = await response.Content.ReadAsStringAsync();
+ exportFile.Should().Contain(_user1.Id);
+ exportFile.Should().Contain(_user2.Id);
+ }
}
}
\ No newline at end of file