Show server errors

users
maxime.batista 1 year ago committed by maxime
parent 182911eac1
commit a05f2486b9

@ -1,7 +1,9 @@
using AdminPanel.Models; using System.Text;
using AdminPanel.Models;
using AdminPanel.Services; using AdminPanel.Services;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.Web;
using Microsoft.Extensions.Primitives;
using MudBlazor; using MudBlazor;
namespace AdminPanel.Pages namespace AdminPanel.Pages
@ -13,10 +15,10 @@ namespace AdminPanel.Pages
[Inject] private ILogger<UserListPanel> Logger { get; init; } [Inject] private ILogger<UserListPanel> Logger { get; init; }
private MudDataGrid<User> Grid { get; set; } private MudDataGrid<User> Grid { get; set; }
private string? SearchString { get; set; } private string? SearchString { get; set; }
private HashSet<User> SelectedItems { get; set; } = new(); private HashSet<User> SelectedItems { get; set; } = new();
@ -31,7 +33,8 @@ namespace AdminPanel.Pages
private async Task<GridData<User>> LoadUsersFromServer(GridState<User> state) private async Task<GridData<User>> LoadUsersFromServer(GridState<User> state)
{ {
Logger.LogDebug($"Loading users from server, state = {state} searchString = {SearchString}"); Logger.LogDebug($"Loading users from server, state = {state} searchString = {SearchString}");
var (count, users) = await Service.ListUsers((uint)(state.Page * state.PageSize), (uint)state.PageSize, SearchString); var (count, users) =
await Service.ListUsers((uint)(state.Page * state.PageSize), (uint)state.PageSize, SearchString);
return new GridData<User> return new GridData<User>
{ {
TotalItems = (int)count, TotalItems = (int)count,
@ -47,10 +50,9 @@ namespace AdminPanel.Pages
{ {
await Service.UpdateUser(user); await Service.UpdateUser(user);
} }
catch (Exception) catch (ServiceException err)
{ {
Snackbar.Add( ShowErrors(err);
"Server responded with errors, your given input may be incorrect.\nIf you entered a new email, verify that the email is not used by another member.");
} }
} }
@ -66,9 +68,25 @@ namespace AdminPanel.Pages
Logger.LogDebug($"Added user : {user}"); Logger.LogDebug($"Added user : {user}");
await Grid.ReloadServerData(); await Grid.ReloadServerData();
} }
catch (Exception) catch (ServiceException err)
{ {
Snackbar.Add("Server responded with errors, your given input may be incorrect."); ShowErrors(err);
}
}
private void ShowErrors(ServiceException e)
{
foreach (var erronedArgument in e.ArgumentMessages)
{
var sb = new StringBuilder(erronedArgument.Key);
sb.Append(" :");
foreach (var message in erronedArgument.Value)
{
sb.Append("\n\t-");
sb.Append(message);
}
Snackbar.Add(sb.ToString());
} }
} }
@ -81,24 +99,23 @@ namespace AdminPanel.Pages
await Service.RemoveUsers(users); await Service.RemoveUsers(users);
await Grid.ReloadServerData(); await Grid.ReloadServerData();
} }
catch (Exception) catch (ServiceException err)
{ {
Snackbar.Add("Server responded with errors"); ShowErrors(err);
} }
} }
private Func<string, string?> VerifyLength(uint min, uint max) private Func<string, string?> VerifyLength(uint min, uint max)
{ {
return s => s.Length >= min && s.Length <= max ? null : $"length is incorrect (must be between {min} and {max})"; return s => s.Length >= min && s.Length <= max
? null
: $"length is incorrect (must be between {min} and {max})";
} }
private void ValidateSearch(KeyboardEventArgs e) private void ValidateSearch(KeyboardEventArgs e)
{ {
if (e.Key == "Enter") Grid.ReloadServerData();
{ Logger.LogDebug($"Searching for {SearchString}");
Grid.ReloadServerData();
Logger.LogDebug($"Searching for {SearchString}");
}
} }
} }
} }

@ -12,7 +12,7 @@ builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services builder.Services
.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); .AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Logging.SetMinimumLevel(LogLevel.Debug); // builder.Logging.SetMinimumLevel(LogLevel.Debug);
var client = new HttpClient var client = new HttpClient
{ {

@ -2,8 +2,8 @@
"iisSettings": { "iisSettings": {
"windowsAuthentication": false, "windowsAuthentication": false,
"anonymousAuthentication": true, "anonymousAuthentication": true,
"iisExpress": { "iisExpress": {
"applicationUrl": "http://localhost:18284", "applicationUrl": "http://localhost:18284",
"sslPort": 0 "sslPort": 0
} }
}, },
@ -12,8 +12,8 @@
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true, "dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "http://localhost:5081", "applicationUrl": "http://localhost:5081",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }

@ -1,3 +1,5 @@
using System.Diagnostics;
using System.Net;
using System.Net.Http.Json; using System.Net.Http.Json;
using AdminPanel.Models; using AdminPanel.Models;
@ -12,30 +14,54 @@ public class HttpUsersService : IUsersService
this.Client = client; this.Client = client;
} }
private record ListUsersResponse(List<User> Users, uint TotalCount); private record ServerErrorMessageDto(string? Field, string? Error, string Message);
public async Task<(uint, List<User>)> ListUsers(uint from, uint len, string? searchString = null) private async Task EnsureResponseIsOk(HttpResponseMessage response)
{ {
var httpResponse = await Client.GetAsync($"/api/admin/list-users?start={from}&n={len}&search={searchString ?? ""}");
httpResponse.EnsureSuccessStatusCode(); if (response.StatusCode == HttpStatusCode.OK)
{
return;
}
var response = await httpResponse.Content.ReadFromJsonAsync<ListUsersResponse>() var content = await response.Content.ReadFromJsonAsync<ServerErrorMessageDto[]>();
?? throw new Exception("Received non-parseable json from server"); var messages = content!
.GroupBy(e => e.Field ?? e.Error!)
.ToDictionary(
g => g.Key,
g => g.ToList().ConvertAll(e => e.Message)
);
throw new ServiceException("Server refused request", messages);
}
private record ListUsersResponseDto(List<User> Users, uint TotalCount);
public async Task<(uint, List<User>)> ListUsers(uint from, uint len, string? searchString = null)
{
var httpResponse =
await Client.GetAsync($"/api/admin/list-users?start={from}&n={len}&search={searchString ?? ""}");
await EnsureResponseIsOk(httpResponse);
var response = await httpResponse.Content.ReadFromJsonAsync<ListUsersResponseDto>()
?? throw new Exception("Received non-parseable json from server");
return (response.TotalCount, response.Users); return (response.TotalCount, response.Users);
} }
private record AddUserRequest(string Username, string Email, string Password, bool IsAdmin); private record AddUserRequestDto(string Username, string Email, string Password, bool IsAdmin);
private record AddUserResponseDto(uint Id);
private record AddUserResponse(uint Id);
public async Task<User> AddUser(string username, string email, string password, bool isAdmin) public async Task<User> AddUser(string username, string email, string password, bool isAdmin)
{ {
var httpResponse = await Client.PostAsJsonAsync("/api/admin/user/add", new AddUserRequest(username, email, password, isAdmin)); var httpResponse = await Client.PostAsJsonAsync("/api/admin/user/add",
httpResponse.EnsureSuccessStatusCode(); new AddUserRequestDto(username, email, password, isAdmin));
await EnsureResponseIsOk(httpResponse);
var response = await httpResponse.Content.ReadFromJsonAsync<AddUserResponse>() var response = await httpResponse.Content.ReadFromJsonAsync<AddUserResponseDto>()
?? throw new Exception("Received non-parseable json from server"); ?? throw new Exception("Received non-parseable json from server");
return new User return new User
{ {
@ -46,19 +72,22 @@ public class HttpUsersService : IUsersService
}; };
} }
private record RemoveUsersRequest(uint[] Identifiers); private record RemoveUsersRequestDto(uint[] Identifiers);
public async Task RemoveUsers(IEnumerable<uint> userIds) public async Task RemoveUsers(IEnumerable<uint> userIds)
{ {
var httpResponse = await Client.PostAsJsonAsync("/api/admin/user/remove-all", new RemoveUsersRequest(userIds.ToArray())); var httpResponse =
httpResponse.EnsureSuccessStatusCode(); await Client.PostAsJsonAsync("/api/admin/user/remove-all", new RemoveUsersRequestDto(userIds.ToArray()));
await EnsureResponseIsOk(httpResponse);
} }
private record UpdateUserRequest(string Email, string Username, bool IsAdmin); private record UpdateUserRequestDto(string Email, string Username, bool IsAdmin);
public async Task UpdateUser(User user) public async Task UpdateUser(User user)
{ {
var httpResponse = await Client.PostAsJsonAsync($"/api/admin/user/{user.Id}/update", new UpdateUserRequest(user.Email, user.Name, user.IsAdmin)); var httpResponse = await Client.PostAsJsonAsync($"/api/admin/user/{user.Id}/update",
httpResponse.EnsureSuccessStatusCode(); new UpdateUserRequestDto(user.Email, user.Name, user.IsAdmin));
await EnsureResponseIsOk(httpResponse);
} }
} }

@ -0,0 +1,18 @@
namespace AdminPanel.Services;
class ServiceException : Exception
{
public Dictionary<string, List<string>> ArgumentMessages { get; init; }
public ServiceException(string? message, Dictionary<string, List<string>> arguments) : base(message)
{
ArgumentMessages = arguments;
}
public ServiceException(string? message, Dictionary<string, List<string>> arguments, Exception? innerException) : base(message, innerException)
{
ArgumentMessages = arguments;
}
}
Loading…
Cancel
Save