update, remove and add new users into the server

users
Maxime BATISTA 11 months ago committed by maxime.batista
parent dc96cc2029
commit 0c06b19e6e

2
.gitignore vendored

@ -60,7 +60,7 @@ dlldata.c
*.pgc
*.pgd
*.rsp
*.sbr
*.sbr
*.tlb
*.tli
*.tlh

@ -7,7 +7,7 @@
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
</PropertyGroup>
<ItemGroup>
<ItemGroup>
<None Include="wwwroot\css\bootstrap\bootstrap.min.css.map" />
<None Include="wwwroot\css\open-iconic\FONT-LICENSE" />
<None Include="wwwroot\css\open-iconic\font\fonts\open-iconic.svg" />
@ -19,7 +19,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.13" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.13" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.13" PrivateAssets="all" />
<PackageReference Include="MudBlazor" Version="6.12.0" />
</ItemGroup>
<ItemGroup>

@ -1,4 +1,8 @@
<Router AppAssembly="@typeof(App).Assembly">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />

@ -2,11 +2,11 @@
@if (@User.IsAdmin)
{
<h3>Administrator @User.UserName</h3>
<h3>Administrator @User.Name</h3>
}
else
{
<h3>@User.UserName</h3>
<h3>@User.Name</h3>
}
<p>email: @User.Email</p>
<p>id: @User.Id</p>

@ -1,5 +1,9 @@
namespace AdminPanel.Models;
public record User(string UserName, string Email, int Id, bool IsAdmin) {
}
public class User
{
public required string Name { get; set; }
public required string Email { get; set; }
public uint Id { get; set; }
public bool IsAdmin { get; set; }
}

@ -1,32 +1,66 @@
@page "/users"
@using AdminPanel.Components;
@using AdminPanel.Models;
@using AdminPanel.Models
<PageTitle>User Panel</PageTitle>
<h1>User Panel</h1>
<div class="users-div">
@if (Users == null)
{
<p>Fetching Data...</p>
}
else
foreach (User user in Users)
{
<div class="user-cell">
<UserComponent User=@user/>
<Leaflet>
<Header>
see more
</Header>
<div id="users-div">
<MudOverlay Visible="IsAddingUser" DarkBackground>
<MudForm id="add-account-form">
<MudTextField T="string" Label="Name" Required @bind-Value="FormAccountName"/>
<MudTextField T="string" Label="Email" Required @bind-Value="FormAccountEmail"/>
<MudTextField T="string" InputType="InputType.Password" Label="Password" Required @bind-Value="FormAccountPassword"/>
<MudCheckBox T="bool" Label="Is Administrator" @bind-Value="FormAccountIsAdmin"/>
<MudButton Variant="Variant.Filled" Color="Color.Secondary" OnClick="@(() => IsAddingUser = false)">Cancel</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="ConfirmAddAccount">Add Account</MudButton>
</MudForm>
</MudOverlay>
<div style="display: flex; align-items: center">
<MudIconButton Icon="@Icons.Material.Filled.Add" OnClick="@(() => IsAddingUser = true)" Color="@Color.Success" Class="add-item-btn"/>
<MudText Align="Align.Center">Add Account</MudText>
</div>
<div style="display: flex; align-items: center">
<MudIconButton Icon="@Icons.Material.Filled.Remove" OnClick="RemoveSelection" Color="@Color.Error" Class="remove-item-btn"/>
<MudText Align="Align.Center">Remove Selection</MudText>
</div>
<Body>
<p>Ratio</p>
</Body>
</Leaflet>
</div>
}
<MudDataGrid
T="User"
MultiSelection="true"
ServerData="LoadUsersFromServer"
ColumnResizeMode="ResizeMode.Column"
RowsPerPage="1"
ReadOnly="false"
EditMode="DataGridEditMode.Form"
@bind-SelectedItems="SelectedItems"
CommittedItemChanges="OnAccountEdited">
<Columns>
<SelectColumn T="User"/>
<PropertyColumn Property="x => x.Name" Required/>
<PropertyColumn Property="x => x.Email" Title="Email Address" Required/>
<TemplateColumn Title="Is Administrator">
<CellTemplate>
<MudCheckBox Value="@context.Item!.IsAdmin" ReadOnly/>
</CellTemplate>
<EditTemplate>
<MudText>Is Administrator :</MudText>
<MudCheckBox @bind-Value="context.Item.IsAdmin"/>
</EditTemplate>
</TemplateColumn>
<PropertyColumn Property="x => x.Id" IsEditable="false"/>
<TemplateColumn>
<CellTemplate>
<MudIconButton Size="Size.Small" Icon="@Icons.Material.Outlined.Edit" OnClick="@context.Actions.StartEditingItemAsync"/>
</CellTemplate>
</TemplateColumn>
</Columns>
<PagerContent>
<MudDataGridPager T="User" PageSizeOptions="new[] { 1, 2, 4, 10, 25, 50, 100 }"/>
</PagerContent>
</MudDataGrid>
</div>

@ -1,34 +1,80 @@
using System.Net.Http.Json;
using System.ComponentModel;
using AdminPanel.Models;
using AdminPanel.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using MudBlazor;
namespace AdminPanel.Pages
{
public partial class UserListPanel
{
public List<User>? Users { get; private set; }
[Inject] public ISnackbar Snackbar { get; private init; }
[Inject] public IUsersService Service { get; private init; }
public UserListPanel()
private HashSet<User> SelectedItems { get; set; } = new();
private string? FormAccountName { get; set; }
private string? FormAccountEmail { get; set; }
private string? FormAccountPassword { get; set; }
private bool FormAccountIsAdmin { get; set; }
public bool IsAddingUser { get; set; }
private async Task<GridData<User>> LoadUsersFromServer(GridState<User> state)
{
HttpClient client = new()
var (count, users) = await Service.ListUsers((uint)(state.Page * state.PageSize), (uint)state.PageSize);
return new GridData<User>
{
BaseAddress = new Uri("http://localhost:8080")
TotalItems = (int)count,
Items = users
};
RetrieveUsers(client);
}
public void OnAccessToUserSpaceClicked(User user)
private async void OnAccountEdited(User user)
{
Console.WriteLine(user.IsAdmin);
try
{
await Service.UpdateUser(user);
}
catch (Exception)
{
Snackbar.Add("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.");
}
}
private async void RetrieveUsers(HttpClient client)
private async void ConfirmAddAccount(MouseEventArgs e)
{
using HttpResponseMessage response = await client.GetAsync("/api/admin/list-users?start=0&n=100");
// We no longer add an account if it is confirmed
IsAddingUser = false;
response.EnsureSuccessStatusCode();
try
{
await Service.AddUser(FormAccountName!, FormAccountEmail!, FormAccountPassword!,
FormAccountIsAdmin);
StateHasChanged();
}
catch (Exception)
{
Snackbar.Add("Server responded with errors, your given input may be incorrect.");
}
}
Users = (await response.Content.ReadFromJsonAsync<List<User>>())!;
StateHasChanged();
Console.WriteLine(Users);
private async void RemoveSelection(MouseEventArgs e)
{
var items = SelectedItems.ToList().ConvertAll(u => u.Id);
Console.WriteLine(items.Count);
try
{
await Service.RemoveUsers(items);
}
catch (Exception)
{
Snackbar.Add("Server responded with errors");
}
}
}
}

@ -0,0 +1,8 @@
#add-account-form {
background-color: white;
visibility: hidden;
color: #ffba00;
}

@ -1,11 +1,26 @@
using AdminPanel;
using AdminPanel.Services;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using MudBlazor.Services;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services
.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
var client = new HttpClient
{
BaseAddress = new Uri("http://localhost:8080")
};
builder.Services.AddScoped<IUsersService>(sp => new HttpUsersService(client));
//builder.Services.AddScoped<IUsersService, UsersServiceStub>();
builder.Services.AddMudServices();
await builder.Build().RunAsync();

@ -0,0 +1,64 @@
using System.Net.Http.Json;
using AdminPanel.Models;
namespace AdminPanel.Services;
public class HttpUsersService : IUsersService
{
private HttpClient Client { get; }
public HttpUsersService(HttpClient client)
{
this.Client = client;
}
private record ListUsersResponse(List<User> Users, uint TotalCount);
public async Task<(uint, List<User>)> ListUsers(uint from, uint len)
{
var httpResponse = await Client.GetAsync($"/api/admin/list-users?start={from}&n={len}");
httpResponse.EnsureSuccessStatusCode();
var response = await httpResponse.Content.ReadFromJsonAsync<ListUsersResponse>()
?? throw new Exception("Received non-parseable json from server");
return (response.TotalCount, response.Users);
}
private record AddUserRequest(string Username, string Email, string Password, bool IsAdmin);
private record AddUserResponse(uint Id);
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));
httpResponse.EnsureSuccessStatusCode();
var response = await httpResponse.Content.ReadFromJsonAsync<AddUserResponse>()
?? throw new Exception("Received non-parseable json from server");
return new User
{
Name = username,
Email = email,
IsAdmin = isAdmin,
Id = response.Id
};
}
private record RemoveUsersRequest(uint[] Identifiers);
public async Task RemoveUsers(IEnumerable<uint> userIds)
{
var httpResponse = await Client.PostAsJsonAsync("/api/admin/user/remove-all", new RemoveUsersRequest(userIds.ToArray()));
httpResponse.EnsureSuccessStatusCode();
}
private record UpdateUserRequest(string Email, string Username, bool IsAdmin);
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));
httpResponse.EnsureSuccessStatusCode();
}
}

@ -0,0 +1,15 @@
using AdminPanel.Models;
namespace AdminPanel.Services
{
public interface IUsersService
{
public Task<(uint, List<User>)> ListUsers(uint from, uint len);
public Task<User> AddUser(string username, string email, string password, bool isAdmin);
public Task RemoveUsers(IEnumerable<uint> userId);
public Task UpdateUser(User user);
}
}

@ -0,0 +1,65 @@
using AdminPanel.Models;
using System.Runtime.CompilerServices;
namespace AdminPanel.Services
{
public class UsersServiceStub : IUsersService
{
private Dictionary<uint, User> Users { get; } = new[]
{
new User
{
Name = "Mathis",
Email = "mathis@gmail.com",
Id = 0,
IsAdmin = true
},
new User
{
Name = "Maeva",
Email = "maeva@gmail.com",
Id = 1,
IsAdmin = false
},
}.ToDictionary(u => u.Id);
public Task<User> AddUser(string username, string email, string password, bool isAdmin)
{
User user = new User
{
Email = email,
Name = username,
IsAdmin = isAdmin,
Id = (uint) Users.Count
};
Users[user.Id] = user;
return Task.FromResult(user);
}
public async Task<(uint, List<User>)> ListUsers(uint from, uint len)
{
//simulate a 1sec long request
await Task.Delay(1000);
var slice = Users.Values
.ToList()
.GetRange((int)from, (int)((from + len > Users.Count) ? Users.Count - from : len));
return ((uint)Users.Count, slice);
}
public Task RemoveUsers(IEnumerable<uint> userIds)
{
foreach (var id in userIds)
{
Users.Remove(id);
}
return Task.CompletedTask;
}
public Task UpdateUser(User user)
{
Users[user.Id] = user;
return Task.CompletedTask;
}
}
}

@ -1,4 +1,8 @@
@inherits LayoutComponentBase
@using MudBlazor
<MudThemeProvider/>
<MudDialogProvider/>
<MudSnackbarProvider/>
<div class="page">
<div class="sidebar">

@ -0,0 +1,9 @@
namespace AdminPanel.Shared
{
public partial class NavMenu
{
}
}

@ -8,3 +8,4 @@
@using Microsoft.JSInterop
@using AdminPanel
@using AdminPanel.Shared
@using MudBlazor

@ -13,9 +13,14 @@
<link href="manifest.json" rel="manifest" />
<link rel="apple-touch-icon" sizes="512x512" href="icon-512.png" />
<link rel="apple-touch-icon" sizes="192x192" href="icon-192.png" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
</head>
<body>
<div id="app">
<svg class="loading-progress">
<circle r="40%" cx="50%" cy="50%" />
@ -29,6 +34,7 @@
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
<script src="_framework/blazor.webassembly.js"></script>
<script>navigator.serviceWorker.register('service-worker.js');</script>
</body>

Loading…
Cancel
Save