diff --git a/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/Media/Index.razor b/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/Media/Index.razor
new file mode 100644
index 000000000..76621e74c
--- /dev/null
+++ b/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/Media/Index.razor
@@ -0,0 +1,7 @@
+@page "/Media"
+<h3>Index of /Media</h3>
+<hr/>
+
+@code {
+
+}
\ No newline at end of file
diff --git a/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/Media/Users.razor b/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/Media/Users.razor
new file mode 100644
index 000000000..81008a258
--- /dev/null
+++ b/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/Media/Users.razor
@@ -0,0 +1,106 @@
+@page "/Media/ByUser"
+@using System.Net.Http.Headers
+@using System.Reflection
+@using Spacebar.AdminApi.Models
+@using Spacebar.AdminAPI.TestClient.Services
+@using ArcaneLibs.Blazor.Components
+@inject Config Config
+@inject ILocalStorageService LocalStorage
+
+<PageTitle>Uploaded media by user</PageTitle>
+
+<details>
+ <summary>Displayed columns</summary>
+ @foreach (var column in DisplayedColumns) {
+ var value = column.Value;
+ <span>
+ <InputCheckbox @bind-Value:get="@(value)" @bind-Value:set="@(b => {
+ DisplayedColumns[column.Key] = b;
+ StateHasChanged();
+ })"/>
+ @column.Key.Name
+ </span>
+ <br/>
+ }
+</details>
+
+<InputSelect @bind-Value="@SelectedUserId">
+ <option value="">All users</option>
+ @if (UserList is { Count: > 0 }) {
+ @foreach (var user in UserList.OrderByDescending(u => u.Id).Where(x => !x.Deleted)) {
+ <option value="@user.Id">@user.Username</option>
+ }
+ }
+</InputSelect>
+
+
+<table class="table table-bordered">
+ @{
+ var columns = DisplayedColumns.Where(kvp => kvp.Value).Select(kvp => kvp.Key).ToList();
+ }
+ <thead>
+ <tr>
+ @foreach (var column in columns) {
+ <th>@column.Name</th>
+ }
+ <th>Actions</th>
+ </tr>
+ </thead>
+ <tbody>
+ @foreach (var user in UserMedia) {
+ <tr>
+ @foreach (var column in columns) {
+ <td>@column.GetValue(user)</td>
+ }
+ <td>
+ <LinkButton href="@($"/Users/Delete/{user.Id}")" Color="#ff0000">Delete</LinkButton>
+ </td>
+ </tr>
+ }
+ </tbody>
+</table>
+
+@code {
+
+ private Dictionary<PropertyInfo, bool> DisplayedColumns { get; set; } = typeof(FileMetadataModel).GetProperties()
+ .ToDictionary(p => p, p => p.Name == "Username" || p.Name == "Id" || p.Name == "MessageCount");
+
+ private List<UserModel> UserList { get; set; } = new();
+ private List<FileMetadataModel> UserMedia { get; set; } = new();
+
+ [SupplyParameterFromQuery(Name = "UserId")]
+ public string? SelectedUserId {
+ get;
+ set {
+ field = value;
+ if (string.IsNullOrWhiteSpace(field))
+ UserMedia.Clear();
+ else _ = GetMediaForUser(value!);
+ }
+ }
+
+ protected override async Task OnInitializedAsync() {
+ using var hc = new HttpClient();
+ hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Config.AccessToken);
+ var response = await hc.GetAsync(Config.AdminUrl + "/_spacebar/admin/users/");
+ if (!response.IsSuccessStatusCode) throw new Exception(await response.Content.ReadAsStringAsync());
+ var content = response.Content.ReadFromJsonAsAsyncEnumerable<UserModel>();
+ await foreach (var user in content) {
+ UserList.Add(user!);
+ StateHasChanged();
+ }
+ }
+
+ private async Task GetMediaForUser(string userId) {
+ using var hc = new HttpClient();
+ hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Config.AccessToken);
+ var response = await hc.GetAsync(Config.AdminUrl + $"/_spacebar/admin/media/user/{userId}/attachments");
+ if (!response.IsSuccessStatusCode) throw new Exception(await response.Content.ReadAsStringAsync());
+ var content = response.Content.ReadFromJsonAsAsyncEnumerable<FileMetadataModel>();
+ await foreach (var media in content) {
+ UserMedia.Add(media!);
+ StateHasChanged();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/Users.razor b/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/Users.razor
index 13c346617..c0e678678 100644
--- a/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/Users.razor
+++ b/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/Users.razor
@@ -4,6 +4,7 @@
@using Spacebar.AdminApi.Models
@using Spacebar.AdminAPI.TestClient.Services
@using ArcaneLibs.Blazor.Components
+@using ArcaneLibs.Extensions
@inject Config Config
@inject ILocalStorageService LocalStorage
@@ -24,6 +25,7 @@
}
</details>
+<p>Got @UserList.Count users.</p>
<table class="table table-bordered">
@{
var columns = DisplayedColumns.Where(kvp => kvp.Value).Select(kvp => kvp.Key).ToList();
@@ -37,7 +39,7 @@
</tr>
</thead>
<tbody>
- @foreach (var user in UserList) {
+ @foreach (var user in UserList.Where(x => !x.Deleted).OrderByDescending(x=>x.MessageCount)) {
<tr>
@foreach (var column in columns) {
<td>@column.GetValue(user)</td>
@@ -58,15 +60,21 @@
private List<UserModel> UserList { get; set; } = new();
protected override async Task OnInitializedAsync() {
- using var hc = new HttpClient();
+ var hc = new StreamingHttpClient();
hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Config.AccessToken);
- var response = await hc.GetAsync(Config.AdminUrl + "/_spacebar/admin/users/");
- if (!response.IsSuccessStatusCode) throw new Exception(await response.Content.ReadAsStringAsync());
- var content = response.Content.ReadFromJsonAsAsyncEnumerable<UserModel>();
- await foreach (var user in content) {
- UserList.Add(user);
- StateHasChanged();
+
+ // var request = new HttpRequestMessage(HttpMethod.Get, Config.AdminUrl + "/_spacebar/admin/users/");
+
+ var response = hc.GetAsyncEnumerableFromJsonAsync<UserModel>(Config.AdminUrl + "/_spacebar/admin/users/");
+ // if (!response.IsSuccessStatusCode) throw new Exception(await response.Content.ReadAsStringAsync());
+ // var content = response.Content.ReadFromJsonAsAsyncEnumerable<UserModel>();
+ await foreach (var user in response) {
+ // Console.WriteLine(user.ToJson(indent: false, ignoreNull: true));
+ UserList.Add(user!);
+ if(UserList.Count % 1000 == 0)
+ StateHasChanged();
}
+ StateHasChanged();
}
}
\ No newline at end of file
diff --git a/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/UsersDelete.razor b/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/UsersDelete.razor
index 084a372fe..98a3e0fc7 100644
--- a/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/UsersDelete.razor
+++ b/extra/admin-api/Utilities/Spacebar.AdminAPI.TestClient/Pages/UsersDelete.razor
@@ -14,15 +14,21 @@ Deleted @ChannelDeleteProgress.Sum(x=>x.Value.Deleted) messages so far!
<progress max="@progress.Total" value="@progress.Deleted"></progress>
}
+@if (Done) {
+ <h1>Done!</h1>
+}
+
@code {
[Parameter]
public required string Id { get; set; }
private Dictionary<string, DeleteProgress> ChannelDeleteProgress { get; set; } = new();
+
+ private bool Done { get; set; }
protected override async Task OnInitializedAsync() {
- using var hc = new HttpClient();
+ var hc = new StreamingHttpClient();
hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Config.AccessToken);
var response = await hc.GetAsync(Config.AdminUrl + $"/_spacebar/admin/Users/{Id}/delete?messageDeleteChunkSize=100");
if (!response.IsSuccessStatusCode) throw new Exception(await response.Content.ReadAsStringAsync());
@@ -47,10 +53,13 @@ Deleted @ChannelDeleteProgress.Sum(x=>x.Value.Deleted) messages so far!
break;
}
}
-
+
StateHasChanged();
await Task.Delay(1);
}
+
+ Done = true;
+ StateHasChanged();
}
private class DeleteProgress {
|