Skip to content
This repository has been archived by the owner on Apr 14, 2023. It is now read-only.

Commit

Permalink
User management refactoring (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucabriguglia authored Aug 10, 2022
1 parent 5799bef commit 2517b02
Show file tree
Hide file tree
Showing 53 changed files with 880 additions and 887 deletions.
2 changes: 1 addition & 1 deletion Atles.sln
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Atles.Models", "src\Atles.M
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Atles.Validators", "src\Atles.Validators\Atles.Validators.csproj", "{558685B8-2B05-486E-9987-7FF6829B0A14}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Atles.Validators.ValidationRules", "src\Atles.Validators.ValidationRules\Atles.Validators.ValidationRules.csproj", "{F821D9F1-CC6E-4A64-9338-DCD790C0FE4B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Atles.Validators.ValidationRules", "src\Atles.Validators.ValidationRules\Atles.Validators.ValidationRules.csproj", "{F821D9F1-CC6E-4A64-9338-DCD790C0FE4B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
14 changes: 6 additions & 8 deletions src/Atles.Client/Models/ReactionCommandModel.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using System;
using Atles.Domain;
using Atles.Domain;

namespace Atles.Client.Models
namespace Atles.Client.Models;

public class ReactionCommandModel
{
public class ReactionCommandModel
{
public PostReactionType PostReactionType { get; set; }
public Guid PostId { get; set; }
}
public PostReactionType PostReactionType { get; set; }
public Guid PostId { get; set; }
}
7 changes: 3 additions & 4 deletions src/Atles.Client/Pages/Admin/Users/Create.razor
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ else
<div class="row">
<div class="col-md-4">
<EditForm Model="Model.User" OnValidSubmit="@(async () => await SaveAsync())">
<DataAnnotationsValidator />
<FluentValidationValidator />
<div class="form-group">
<label for="email" class="control-label">@Localizer["Email"]</label>
<InputText id="email" @bind-Value="Model.User.Email" Class="form-control" />
Expand All @@ -41,13 +41,12 @@ else
<input type="submit" value="Save" class="btn btn-primary" />
<button type="button" class="btn btn-secondary" @onclick="Cancel">@Localizer["Cancel"]</button>
</div>
<ValidationSummary />
</EditForm>
</div>
</div>
}

@if (Error)
@if (HasError)
{
<SomethingWrong />
<SomethingWrong Error="@Error" />
}
56 changes: 29 additions & 27 deletions src/Atles.Client/Pages/Admin/Users/Create.razor.cs
Original file line number Diff line number Diff line change
@@ -1,39 +1,41 @@
using System;
using System.Text.Json;
using System.Threading.Tasks;
using System.Text.Json;
using Atles.Client.Components.Admin;
using Atles.Client.Models;
using Atles.Models;
using Atles.Models.Admin.Users;

namespace Atles.Client.Pages.Admin.Users
namespace Atles.Client.Pages.Admin.Users;

public abstract class CreatePage : AdminPageBase
{
public abstract class CreatePage : AdminPageBase
protected CreateUserPageModel Model { get; set; }
protected bool HasError { get; set; }
protected string Error { get; set; }

protected override async Task OnInitializedAsync()
{
protected CreatePageModel Model { get; set; }
protected bool Error { get; set; }
Model = await ApiService.GetFromJsonAsync<CreateUserPageModel>("api/admin/users/create");
}

protected override async Task OnInitializedAsync()
protected async Task SaveAsync()
{
var response = await ApiService.PostAsJsonAsync("api/admin/users/save", Model.User);
var content = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
Model = await ApiService.GetFromJsonAsync<CreatePageModel>("api/admin/users/create");
var userId = JsonSerializer.Deserialize<Guid>(content);
NavigationManager.NavigateTo($"/admin/users/edit/{userId}");
}

protected async Task SaveAsync()
else
{
var response = await ApiService.PostAsJsonAsync("api/admin/users/save", Model.User);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
var userId = JsonSerializer.Deserialize<Guid>(content);
NavigationManager.NavigateTo($"/admin/users/edit/{userId}");
}
else
{
Error = true;
}
HasError = true;
var problemDetails = JsonSerializer.Deserialize<ProblemDetails>(content);
Error = problemDetails?.Detail;
}
}

protected void Cancel()
{
NavigationManager.NavigateTo("/admin/users");
}
protected void Cancel()
{
NavigationManager.NavigateTo("/admin/users");
}
}
}
2 changes: 1 addition & 1 deletion src/Atles.Client/Pages/Admin/Users/Edit.razor
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ else
</div>
</div>

<Form Model="Model" Button="Update" OnValidSubmit="@UpdateAsync"></Form>
<Form Model="Model.User" SubmitButtonText="Update" OnSubmit="@UpdateAsync" OnCancel="Cancel"></Form>

<div>
<a class="btn btn-outline-info mb-3" data-toggle="collapse" href="#info" role="button" aria-expanded="false" aria-controls="info">
Expand Down
46 changes: 24 additions & 22 deletions src/Atles.Client/Pages/Admin/Users/Edit.razor.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
using System;
using System.Threading.Tasks;
using Atles.Client.Components.Admin;
using Atles.Client.Components.Admin;
using Atles.Models.Admin.Users;
using Microsoft.AspNetCore.Components;

namespace Atles.Client.Pages.Admin.Users
namespace Atles.Client.Pages.Admin.Users;

public abstract class EditPage : AdminPageBase
{
public abstract class EditPage : AdminPageBase
{
[Parameter] public Guid Id { get; set; }
[Parameter] public string IdentityUserId { get; set; }
[Parameter] public Guid Id { get; set; }
[Parameter] public string IdentityUserId { get; set; }

protected EditPageModel Model { get; set; }
protected EditUserPageModel Model { get; set; }

protected override async Task OnParametersSetAsync()
{
var requestUri = string.IsNullOrWhiteSpace(IdentityUserId)
? $"api/admin/users/edit/{Id}"
: $"api/admin/users/edit-by-identity-user-id/{IdentityUserId}";

protected override async Task OnParametersSetAsync()
{
var requestUri = string.IsNullOrWhiteSpace(IdentityUserId)
? $"api/admin/users/edit/{Id}"
: $"api/admin/users/edit-by-identity-user-id/{IdentityUserId}";
Model = await ApiService.GetFromJsonAsync<EditUserPageModel>(requestUri);
}

Model = await ApiService.GetFromJsonAsync<EditPageModel>(requestUri);
}
protected async Task UpdateAsync()
{
await ApiService.PostAsJsonAsync("api/admin/users/update", Model.User);
NavigationManager.NavigateTo("/admin/users");
}

protected async Task UpdateAsync()
{
await ApiService.PostAsJsonAsync("api/admin/users/update", Model);
NavigationManager.NavigateTo("/admin/users");
}
protected void Cancel()
{
NavigationManager.NavigateTo("/admin/users");
}
}
}
12 changes: 6 additions & 6 deletions src/Atles.Client/Pages/Admin/Users/Form.razor
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

<div class="row">
<div class="col-md-4">
<EditForm EditContext="@EditContext" OnSubmit="OnSubmitAsync">
<DataAnnotationsValidator />
<EditForm Model="Model" OnValidSubmit="OnSubmit">
<FluentValidationValidator />
<div class="form-group">
<label for="displayName" class="control-label">@Localizer["Display Name"]</label>
<InputText id="displayName" @bind-Value="Model.User.DisplayName" Class="form-control" />
<ValidationMessage For="@(() => Model.User.DisplayName)" />
<InputText id="displayName" @bind-Value="Model.DisplayName" Class="form-control" />
<ValidationMessage For="@(() => Model.DisplayName)" />
</div>
@if (Model.Roles.Count > 0)
{
Expand All @@ -22,8 +22,8 @@
</div>
}
<div class="form-group">
<input type="submit" value="@Button" class="btn btn-primary mb-1" />
<button type="button" class="btn btn-secondary mb-1" @onclick="Cancel">@Localizer["Cancel"]</button>
<input type="submit" value="@SubmitButtonText" class="btn btn-primary mb-1" />
<button type="button" class="btn btn-secondary mb-1" @onclick="OnCancel">@Localizer["Cancel"]</button>
</div>
<ValidationSummary />
</EditForm>
Expand Down
73 changes: 7 additions & 66 deletions src/Atles.Client/Pages/Admin/Users/Form.razor.cs
Original file line number Diff line number Diff line change
@@ -1,70 +1,11 @@
using System.Threading.Tasks;
using Atles.Client.Components.Admin;
using Atles.Client.Components.Admin;
using Atles.Models.Admin.Users;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;

namespace Atles.Client.Pages.Admin.Users
{
public abstract class FormComponent : AdminComponentBase
{
[Parameter] public EditPageModel Model { get; set; }
[Parameter] public string Button { get; set; }
[Parameter] public EventCallback OnValidSubmit { get; set; }

protected EditContext EditContext;
private ValidationMessageStore _validationMessageStore;
private string _currentDisplayName;

protected override void OnInitialized()
{
EditContext = new EditContext(Model.User);
EditContext.OnFieldChanged += HandleFieldChanged;
_validationMessageStore = new ValidationMessageStore(EditContext);
_currentDisplayName = Model.User.DisplayName;
}

private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
{
_validationMessageStore.Clear(e.FieldIdentifier);
}

protected async Task OnSubmitAsync()
{
if (EditContext.Validate())
{
if (await NameIsUniqueAsync(EditContext))
{
await OnValidSubmit.InvokeAsync(null);
}
else
{
var fieldIdentifier = new FieldIdentifier(EditContext.Model, "DisplayName");
_validationMessageStore.Clear(fieldIdentifier);
_validationMessageStore.Add(fieldIdentifier, Localizer["A user with the same display name already exists."]);
EditContext.NotifyValidationStateChanged();
}
}
}
namespace Atles.Client.Pages.Admin.Users;

private async Task<bool> NameIsUniqueAsync(EditContext editContext)
{
var displayNameProp = editContext.Model.GetType().GetProperty("DisplayName");
var displayNameVal = displayNameProp.GetValue(editContext.Model).ToString();

var isDisplayNameUnique = displayNameVal == _currentDisplayName || await ApiService.GetFromJsonAsync<bool>($"api/admin/users/is-display-name-unique/{displayNameVal}");

return isDisplayNameUnique;
}

public void Dispose()
{
EditContext.OnFieldChanged -= HandleFieldChanged;
}

protected void Cancel()
{
NavigationManager.NavigateTo("/admin/users");
}
}
}
public abstract class FormComponent : AdminFormBase
{
[Parameter] public EditUserPageModel.UserModel Model { get; set; }
[Parameter] public string SubmitButtonText { get; set; }
}
7 changes: 7 additions & 0 deletions src/Atles.Client/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
using Atles.Models.Admin.Categories;
using Atles.Models.Admin.Forums;
using Atles.Models.Admin.PermissionSets;
using Atles.Models.Admin.Users;
using Atles.Models.Public;
using Atles.Validators;
using Atles.Validators.Users;
using Atles.Validators.ValidationRules;
using FluentValidation;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Tewr.Blazor.FileReader;
using SettingsPageModel = Atles.Models.Admin.Sites.SettingsPageModel;

namespace Atles.Client;

Expand Down Expand Up @@ -62,10 +65,14 @@ public static async Task Main(string[] args)
builder.Services.AddTransient<IForumValidationRules, ApiForumValidationRules>();
builder.Services.AddTransient<IPermissionSetValidationRules, ApiPermissionSetValidationRules>();
builder.Services.AddTransient<ITopicValidationRules, ApiTopicValidationRules>();
builder.Services.AddTransient<IUserValidationRules, ApiUserValidationRules>();

builder.Services.AddTransient<IValidator<CategoryFormModel.CategoryModel>, CategoryValidator>();
builder.Services.AddTransient<IValidator<ForumFormModel.ForumModel>, ForumValidator>();
builder.Services.AddTransient<IValidator<PermissionSetFormModel.PermissionSetModel>, PermissionSetValidator>();
builder.Services.AddTransient<IValidator<SettingsPageModel.SiteModel>, SiteValidator>();
builder.Services.AddTransient<IValidator<CreateUserPageModel.UserModel>, CreateUserValidator>();
builder.Services.AddTransient<IValidator<EditUserPageModel.UserModel>, UpdateUserValidator>();

builder.Services.AddFileReaderService(o => o.UseWasmSharedBuffer = true);

Expand Down
4 changes: 2 additions & 2 deletions src/Atles.Client/Shared/SomethingWrong.razor
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@inject IStringLocalizer<SharedResources> Loc
@inherits Atles.Client.Shared.SomethingWrongComponent

<div class="alert alert-danger mt-2" role="alert">
@Loc["Ops something went wrong."]
@Message
</div>
16 changes: 16 additions & 0 deletions src/Atles.Client/Shared/SomethingWrong.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Components;
using Atles.Client.Components.Shared;

namespace Atles.Client.Shared;

public abstract class SomethingWrongComponent : SharedComponentBase
{
[Parameter] public string Error { get; set; }

public string Message { get; set; }

protected override void OnInitialized()
{
Message = !string.IsNullOrEmpty(Error) ? Error : Loc["Ops something went wrong."];
}
}
20 changes: 20 additions & 0 deletions src/Atles.Client/ValidationRules/ApiUserValidationRules.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Atles.Client.Services.Api;
using Atles.Validators.ValidationRules;

namespace Atles.Client.ValidationRules;

public class ApiUserValidationRules : IUserValidationRules
{
private readonly ApiService _apiService;

public ApiUserValidationRules(ApiService apiService)
{
_apiService = apiService;
}

public async Task<bool> IsUserEmailUnique(Guid id, string email) =>
await _apiService.GetFromJsonAsync<bool>($"api/admin/users/is-email-unique/{id}/{email}");

public async Task<bool> IsUserDisplayNameUnique(Guid id, string displayName) =>
await _apiService.GetFromJsonAsync<bool>($"api/admin/users/is-display-name-unique/{id}/{displayName}");
}
Loading

0 comments on commit 2517b02

Please sign in to comment.