Skip to content

Commit

Permalink
#115 chore: added account page to change username/password
Browse files Browse the repository at this point in the history
  • Loading branch information
joseantmazonsb committed Mar 22, 2022
1 parent f27c815 commit 866bea4
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 13 deletions.
177 changes: 177 additions & 0 deletions Linguard/Web/Pages/Account.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
@page "/account"
@using Linguard.Core.Utils
@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Identity
@using System.Security.Claims
@using Linguard.Web.Services

<PageTitle>@($"{AssemblyInfo.Product} | {Title}")</PageTitle>

<RadzenHeading Text="@Title" class="mb-3"/>

<RadzenCard class="mb-2">
<RadzenTemplateForm class="align-items-center" Data="@("")">
<RadzenTabs SelectedIndex="0" RenderMode="TabRenderMode.Server">
<Tabs>
<RadzenTabsItem Text="Details">
<div class="row">
<div class="col-xxl">
<div class="row">
<div class=" mb-2">
<RadzenLabel Text="Username"/>
</div>
</div>
<div class="row">
<div class="col-xxl-3">
<RadzenTextBox @bind-Value="_user.UserName" class="w-100"/>
</div>
</div>
<div class="row mt-3">
<div class="col">
<RadzenButton ButtonType="ButtonType.Button" Icon="save" Text="Save" class="me-2"
ButtonStyle="ButtonStyle.Primary" Click="Save"/>
</div>
</div>
</div>
</div>
</RadzenTabsItem>
<RadzenTabsItem Text="Password">
<div class="row">
<div class="col-xxl">
<div class="row mb-2">
<div class="col">
<RadzenLabel Text="Current password"/>
</div>
</div>
<div class="row">
<div class="col-xxl-3">
<RadzenPassword @ref="_currentPassword" class="w-100"/>
</div>
</div>
<div class="row my-2">
<div class="col">
<RadzenLabel Text="New password"/>
</div>
</div>
<div class="row">
<div class="col-xxl-3">
<RadzenPassword @ref="_newPassword" class="w-100"/>
</div>
</div>
<div class="row my-2">
<div class="col">
<RadzenLabel Text="Confirm new password"/>
</div>
</div>
<div class="row">
<div class="col-xxl-3">
<RadzenPassword @ref="_confirmNewPassword" class="w-100"/>
</div>
</div>
<div class="row mt-3">
<div class="col">
<RadzenButton ButtonType="ButtonType.Button" Icon="save" Text="Save" class="me-2"
ButtonStyle="ButtonStyle.Primary" Click="ChangePassword"/>
</div>
</div>
</div>
</div>
</RadzenTabsItem>
</Tabs>
</RadzenTabs>
</RadzenTemplateForm>
</RadzenCard>

@inject NotificationService _notificationService
@inject ILogger _logger
@inject AuthenticationStateProvider _authenticationStateProvider
@inject UserManager<IdentityUser> _userManager
@inject IStateHasChangedNotifierService _notifier

@code {
private const string Title = "Account";
private IdentityUser _user;
private RadzenPassword _currentPassword;
private RadzenPassword _newPassword;
private RadzenPassword _confirmNewPassword;


protected override async Task OnInitializedAsync() {
var authState = await _authenticationStateProvider.GetAuthenticationStateAsync();
var userId = authState.User.Claims.SingleOrDefault(c => c.Type.Equals(ClaimTypes.NameIdentifier));
_user = await _userManager.FindByIdAsync(userId?.Value);
}

private async Task Save() {
try {
await _userManager.UpdateAsync(_user);
_notificationService.Notify(new NotificationMessage {
Severity = NotificationSeverity.Success,
Summary = "Account updated!"
});
_notifier.Notify();
}
catch (Exception e) {
_notificationService.Notify(new NotificationMessage {
Severity = NotificationSeverity.Error,
Summary = "Failed to update account",
Detail = e.Message
});
}
}

private async Task ChangePassword() {
var result = await IsPasswordValid();
if (!result) return;
try {
await _userManager.ChangePasswordAsync(_user, _currentPassword.Value, _newPassword.Value);
// TODO not working
// _currentPassword.Value = string.Empty;
// _newPassword.Value = string.Empty;
// _confirmNewPassword.Value = string.Empty;
_notificationService.Notify(new NotificationMessage {
Severity = NotificationSeverity.Success,
Summary = "Password updated!"
});
StateHasChanged();
}
catch (Exception e) {
_notificationService.Notify(new NotificationMessage {
Severity = NotificationSeverity.Error,
Summary = "Unable to update password!",
Detail = e.Message
});
}
}

private async Task<bool> IsPasswordValid() {
var passwordOk = !string.IsNullOrEmpty(_currentPassword.Value)
&& await _userManager.CheckPasswordAsync(_user, _currentPassword.Value);
if (!passwordOk) {
_notificationService.Notify(new NotificationMessage {
Severity = NotificationSeverity.Error,
Summary = "Unable to update password!",
Detail = "Current password is not correct."
});
return await Task.FromResult(false);
}
if (string.IsNullOrEmpty(_newPassword.Value) || string.IsNullOrEmpty(_confirmNewPassword.Value)) {
_notificationService.Notify(new NotificationMessage {
Severity = NotificationSeverity.Error,
Summary = "Unable to update password!",
Detail = "Password cannot be empty."
});
return await Task.FromResult(false);
}
if (!_newPassword.Value.Equals(_confirmNewPassword.Value)) {
_notificationService.Notify(new NotificationMessage {
Severity = NotificationSeverity.Error,
Summary = "Unable to update password!",
Detail = "Passwords do not match."
});
return await Task.FromResult(false);
}
return await Task.FromResult(true);
}

}
14 changes: 7 additions & 7 deletions Linguard/Web/Pages/Settings.razor
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@
</Tabs>
</RadzenTabs>
<div class="row mt-2 d-flex">
<div class="col-md-12 align-items-end">
<RadzenButton ButtonType="ButtonType.Submit" Icon="save" Text="Save" class="me-2"
ButtonStyle="ButtonStyle.Primary"/>
<RadzenButton ButtonType="ButtonType.Button" Icon="download" title="Download"
ButtonStyle="ButtonStyle.Secondary"
Click="@_webHelper.DownloadConfiguration" />
</div>
<div class="col-md-12 align-items-end">
<RadzenButton ButtonType="ButtonType.Submit" Icon="save" Text="Save" class="me-2"
ButtonStyle="ButtonStyle.Primary"/>
<RadzenButton ButtonType="ButtonType.Button" Icon="download" title="Download"
ButtonStyle="ButtonStyle.Secondary"
Click="@_webHelper.DownloadConfiguration" />
</div>
</div>
</RadzenTemplateForm>
</RadzenCard>

Expand Down
2 changes: 1 addition & 1 deletion Linguard/Web/Pages/Signup.razor
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<PageTitle>@($"{AssemblyInfo.Product} | Sign up")</PageTitle>

<RadzenHeading Text="Welcome!" class="mb-3 text-center"/>
<RadzenHeading Text="Create an account" class="mb-3 text-center"/>
<RadzenCard class="w-100" Style="margin-bottom: 10rem">
<RadzenTemplateForm class="align-items-center" Data="@_user">
<div class="row">
Expand Down
4 changes: 3 additions & 1 deletion Linguard/Web/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#region Web services

builder.Services.AddSingleton<IWebService, WebService>();
builder.Services.AddSingleton<IStateHasChangedNotifierService, StateHasChangedNotifierService>();
builder.Services.AddTransient<IWebHelper, WebHelper>();
builder.Services.AddTransient<QRCodeGenerator, QRCodeGenerator>();
builder.Services.AddTransient<ILifetimeService, LifetimeService>();
Expand All @@ -61,14 +62,15 @@
#region Authentication

builder.Services.AddDbContext<ApplicationDbContext>();
builder.Services.AddTransient<IdentityDbContext, ApplicationDbContext>();
builder.Services.AddScoped<IdentityDbContext, ApplicationDbContext>();
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddIdentityCore<IdentityUser>(options => {
options.SignIn.RequireConfirmedAccount = false;
options.Password.RequireDigit = false;
options.Password.RequiredLength = 1;
options.Password.RequireUppercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireLowercase = false;
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
Expand Down
7 changes: 7 additions & 0 deletions Linguard/Web/Services/IStateHasChangedNotifierService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Linguard.Web.Services;

public interface IStateHasChangedNotifierService {
void Subscribe(EventHandler handler);
void UnSubscribe(EventHandler handler);
void Notify();
}
18 changes: 18 additions & 0 deletions Linguard/Web/Services/StateHasChangedNotifierService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Linguard.Web.Services;

public class StateHasChangedNotifierService : IStateHasChangedNotifierService {
private readonly ISet<EventHandler> _handlers = new HashSet<EventHandler>();
public void Subscribe(EventHandler handler) {
_handlers.Add(handler);
}

public void UnSubscribe(EventHandler handler) {
_handlers.Remove(handler);
}

public void Notify() {
foreach (var handler in _handlers) {
handler.Invoke(this, EventArgs.Empty);
}
}
}
14 changes: 10 additions & 4 deletions Linguard/Web/Shared/ProfileMenu.razor
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@
@inject AuthenticationStateProvider _authenticationStateProvider
@inject IJSRuntime _jsRuntime
@inject IAuthenticationService _authenticationService
@inject UserManager<IdentityUser> _userManager
@inject IStateHasChangedNotifierService _notifier

@code {

string? _user;
IdentityUser? _user;
string? _email;
string GreetingMessage => $"Hi, {_user}";
string GreetingMessage => $"Hi, {_user?.UserName}";
string GravatarEmail => _email ?? "[email protected]";

async Task OnStyleChanged(string value) {
Expand All @@ -44,8 +46,12 @@

protected override async Task OnInitializedAsync() {
await base.OnInitializedAsync();
var state = await _authenticationStateProvider.GetAuthenticationStateAsync();
_user = state.User.Identity?.Name;
var authState = await _authenticationStateProvider.GetAuthenticationStateAsync();
var userId = authState.User.Claims.SingleOrDefault(c => c.Type.Equals(ClaimTypes.NameIdentifier));
_user = await _userManager.FindByIdAsync(userId?.Value);
_notifier.Subscribe((_, _) => {
StateHasChanged();
});
}

private void Logout() {
Expand Down
1 change: 1 addition & 0 deletions Linguard/WebMock/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#region Web services

builder.Services.AddSingleton<IWebService, WebService>();
builder.Services.AddSingleton<IStateHasChangedNotifierService, StateHasChangedNotifierService>();
builder.Services.AddTransient<IWebHelper, WebHelper>();
builder.Services.AddTransient<QRCodeGenerator, QRCodeGenerator>();
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
Expand Down

0 comments on commit 866bea4

Please sign in to comment.