Skip to content

Commit

Permalink
Merge pull request #649 from neozhu/fixcreateuser
Browse files Browse the repository at this point in the history
🐛 fixed create user step in administrator
  • Loading branch information
neozhu committed Apr 7, 2024
2 parents 13dd227 + 922c747 commit e720a4d
Show file tree
Hide file tree
Showing 29 changed files with 299 additions and 47 deletions.
2 changes: 1 addition & 1 deletion src/Application/Application.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.3" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="8.0.3" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.10" />
<PackageReference Include="Hangfire.Core" Version="1.8.11" />
<PackageReference Include="Hangfire.Core" Version="1.8.12" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Domain\Domain.csproj" />
Expand Down
2 changes: 0 additions & 2 deletions src/Infrastructure/DependencyInjection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,6 @@ private static IServiceCollection AddServices(this IServiceCollection services)
services.Configure<IdentityOptions>(options =>
{
var identitySettings = configuration.GetRequiredSection(IdentitySettings.Key).Get<IdentitySettings>();
// Password settings
options.Password.RequireDigit = identitySettings!.RequireDigit;
options.Password.RequiredLength = identitySettings.RequiredLength;
Expand Down
7 changes: 4 additions & 3 deletions src/Server.UI/Pages/Identity/Authentication/Login.razor
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,17 @@
var user = await SignInManager.GetTwoFactorAuthenticationUserAsync();
var token = await UserManager.GenerateTwoFactorTokenAsync(user, "Email");
await Sender.Publish(new SendFactorCodeNotification(user.Email, user.UserName, token));

RedirectManager.RedirectTo(LoginWith2fa.PageUrl, new() { ["returnUrl"] = ReturnUrl, ["rememberMe"] = Input.RememberMe });


}
else if (result.IsLockedOut)
{
Logger.LogWarning($"{Input.UserName} account locked out.");
RedirectManager.RedirectTo(Lockout.PageUrl);
}
else if (result.IsNotAllowed)
{
errorMessage = L["Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps."];
}
else
{
errorMessage = L["Error: Invalid login attempt."];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
<MudItem xs="12" sm="6">
<MudText Typo="Typo.caption">@L["Status"]</MudText>
<div class="d-fex">
<MudCheckBox For="@(() => Model.IsActive)" T="bool" @bind-Value="Model.IsActive" Label="@L["Is Active"]" Disabled="@(string.IsNullOrEmpty(Model.Id))"></MudCheckBox>
<MudCheckBox For="@(() => Model.IsActive)" Disabled="@(!string.IsNullOrEmpty(Model.Id))" T="bool" @bind-Value="Model.IsActive" Label="@L["Is Active"]"></MudCheckBox>
</div>
</MudItem>
<MudItem xs="12" sm="12">
Expand Down
129 changes: 92 additions & 37 deletions src/Server.UI/Pages/Identity/Users/Users.razor
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
@page "/identity/users"
@using CleanArchitecture.Blazor.Application.Features.Identity.Notifications.ResetPassword
@using CleanArchitecture.Blazor.Application.Features.Identity.Notifications.SendWelcome
@using FluentEmail.Core.Models
@using Microsoft.AspNetCore.WebUtilities
@using Severity = Severity
@using LazyCache
@using CleanArchitecture.Blazor.Application.Features.Identity.DTOs
Expand All @@ -15,11 +18,13 @@
@using CleanArchitecture.Blazor.Infrastructure.Constants.Role
@using System.Reflection
@using CleanArchitecture.Blazor.Infrastructure.Constants.ClaimTypes
@using System.Text

@attribute [Authorize(Policy = Permissions.Users.View)]
@inherits OwningComponentBase
@implements IDisposable

@inject IMediator Sender
@inject NavigationManager NavigationManager
@inject IUsersStateContainer UsersStateContainer
@inject IBlazorDownloadFileService BlazorDownloadFileService
@inject IUserService UserService
Expand Down Expand Up @@ -202,7 +207,7 @@
}
@if (_canRestPassword)
{
<MudMenuItem OnAction=@(() => OnResetPassword(context.Item))>@L["Reset Password"]</MudMenuItem>
<MudMenuItem Disabled="@(!context.Item.IsActive)" OnAction=@(() => OnResetPassword(context.Item))>@L["Reset Password"]</MudMenuItem>
}
</MudMenu>
}
Expand Down Expand Up @@ -323,6 +328,7 @@
[CascadingParameter] private Task<AuthenticationState> AuthState { get; set; } = default!;
private UserManager<ApplicationUser> UserManager;
private RoleManager<ApplicationRole> RoleManager;

private int _defaultPageSize = 15;
private HashSet<ApplicationUserDto> _selectedItems = new();
private readonly ApplicationUserDto _currentDto = new();
Expand Down Expand Up @@ -453,33 +459,36 @@
PhoneNumber = model.PhoneNumber,
SuperiorId = model.SuperiorId,
ProfilePictureDataUrl = model.ProfilePictureDataUrl,
IsActive = false
EmailConfirmed = true,
IsActive = model.IsActive
};
var state = await UserManager.CreateAsync(applicationUser);
if (state.Succeeded)
var identityResult = await UserManager.CreateAsync(applicationUser);
if (!identityResult.Succeeded)
{
if (model.AssignedRoles is not null && model.AssignedRoles.Length > 0)
{
await UserManager.AddToRolesAsync(applicationUser, model.AssignedRoles);
}
else
{
await UserManager.AddToRoleAsync(applicationUser, RoleName.Basic);
}
Snackbar.Add($"{ConstantString.CreateSuccess}", Severity.Info);
Logger.LogInformation("Create a user succeeded. Username: {@UserName:l}, UserId: {@UserId}", applicationUser.UserName, applicationUser.Id);
UserService.Refresh();
await OnRefresh();
var response = await SendWelcome(applicationUser.Email, applicationUser.UserName!);
if (response.Successful == false)
{
Snackbar.Add(string.Format(L["{0}"], response.ErrorMessages.FirstOrDefault()), Severity.Error);
}
Snackbar.Add($"{string.Join(",", identityResult.Errors.Select(x => x.Description).ToArray())}", Severity.Error);
return;
}
Snackbar.Add($"{L["New user created successfully."]}", Severity.Info);
if (model.AssignedRoles is not null && model.AssignedRoles.Length > 0)
{
await UserManager.AddToRolesAsync(applicationUser, model.AssignedRoles);
}
else
{
Snackbar.Add($"{string.Join(",", state.Errors.Select(x => x.Description).ToArray())}", Severity.Error);
await UserManager.AddToRoleAsync(applicationUser, RoleName.Basic);
}
if (applicationUser.IsActive)
{
var code = await UserManager.GeneratePasswordResetTokenAsync(applicationUser);
await SendRestPasswordNotification(code, applicationUser.Id, applicationUser.Email, applicationUser.UserName);
Snackbar.Add($"Recovery email sent. Please check your inbox to set a new password.", Severity.Info);
}

Logger.LogInformation("Create a user succeeded. Username: {@UserName:l}, UserId: {@UserId}", applicationUser.UserName, applicationUser.Id);
UserService.Refresh();
await OnRefresh();


}
}

Expand Down Expand Up @@ -518,7 +527,7 @@
{
await UserManager.AddToRolesAsync(user, item.AssignedRoles);
}
Snackbar.Add($"{ConstantString.SaveSuccess}", Severity.Info);
Snackbar.Add($"{L["The user updated successfully."]}", Severity.Info);
await OnRefresh();
UserService.Refresh();
}
Expand Down Expand Up @@ -624,17 +633,45 @@
private async Task OnSetActive(ApplicationUserDto item)
{
var user = await UserManager.FindByIdAsync(item.Id!) ?? throw new NotFoundException($"Application user not found {item.Id}.");
user.IsActive = !item.IsActive;
var state = await UserManager.UpdateAsync(user);
item.IsActive = !item.IsActive;
if (state.Succeeded)
if (!user.IsActive)
{
Snackbar.Add($"{ConstantString.UpdateSuccess}", Severity.Info);
var code = await UserManager.GeneratePasswordResetTokenAsync(user);
await SendRestPasswordNotification(code, user.Id, user.Email, user.UserName);
Snackbar.Add($"Email sent. Please check your inbox to set a new password.", Severity.Info);

user.IsActive = true;
user.LockoutEnd = null;
var identityResult = await UserManager.UpdateAsync(user);
if (identityResult.Succeeded)
{
item.IsActive = true;
item.LockoutEnd = null;
Snackbar.Add($"{L["The user has been activated."]}", Severity.Info);
}
else
{
Snackbar.Add($"{string.Join(",", identityResult.Errors.Select(x => x.Description).ToArray())}", Severity.Error);
}

}
else
{
Snackbar.Add($"{string.Join(",", state.Errors.Select(x => x.Description).ToArray())}", Severity.Error);
user.IsActive = false;
user.LockoutEnd = DateTimeOffset.MaxValue;
var identityResult = await UserManager.UpdateAsync(user);

if (identityResult.Succeeded)
{
item.IsActive = false;
item.LockoutEnd = DateTimeOffset.MaxValue;
Snackbar.Add($"{L["The user has been inactivated."]}", Severity.Info);
}
else
{
Snackbar.Add($"{string.Join(",", identityResult.Errors.Select(x => x.Description).ToArray())}", Severity.Error);
}
}

}

private async Task OnResetPassword(ApplicationUserDto item)
Expand All @@ -649,11 +686,17 @@
var result = await dialog.Result;
if (!result.Canceled)
{
var user = await UserManager.FindByIdAsync(item.Id!);
var user = await UserManager.FindByIdAsync(item.Id!) ?? throw new NotFoundException($"Application user not found {item.Id}.");

var token = await UserManager.GeneratePasswordResetTokenAsync(user!);
var state = await UserManager.ResetPasswordAsync(user!, token, model!.Password!);
if (state.Succeeded)
{
if (user.EmailConfirmed == false)
{
user.EmailConfirmed = true;
await UserManager.UpdateAsync(user);
}
Snackbar.Add($"{L["Reset password successfully"]}", Severity.Info);
}
else
Expand Down Expand Up @@ -817,15 +860,15 @@
}).ToListAsync();
var result = await ExcelService.ExportAsync(items,
new Dictionary<string, Func<ApplicationUserDto, object?>>
{
{
{ L["Id"], item => item.Id },
{ L["User Name"], item => item.UserName },
{ L["Display Name"], item => item.DisplayName },
{ L["Email"], item => item.Email },
{ L["Phone Number"], item => item.PhoneNumber },
{ L["Tenant Id"], item => item.TenantId },
{ L["Tenant Name"], item => item.TenantName }
}, L["Users"]);
}, L["Users"]);
var downloadResult = await BlazorDownloadFileService.DownloadFile($"{L["Users"]}.xlsx", result, "application/octet-stream");
Snackbar.Add($"{ConstantString.ExportSuccess}", Severity.Info);
}
Expand Down Expand Up @@ -883,10 +926,22 @@

_uploading = false;
}
private Task<SendResponse> SendWelcome(string toEmail, string userName)
private async Task SendWelcomeNotification(string toEmail, string userName)
{
var callbackUrl = NavigationManager.GetUriWithQueryParameters(
NavigationManager.ToAbsoluteUri(Login.PageUrl).AbsoluteUri,
new Dictionary<string, object?> { ["returnUrl"] = "/" });

await Sender.Publish(new SendWelcomeNotification(callbackUrl, toEmail, userName));
Logger.LogInformation("{UserName} Activated Successfully!", toEmail);
}
private async Task SendRestPasswordNotification(string code, string userId, string toEmail, string userName)
{
var subject = string.Format(L["Welcome to {0}"], ApplicationSettings.AppName);
var LoginUrl = $"{ApplicationSettings.ApplicationUrl}/pages/authentication/login";
return MailService.SendAsync(toEmail, subject, "_welcome", new { LoginUrl, ApplicationSettings.AppName, Email = toEmail, UserName = userName, ApplicationSettings.Company });
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = NavigationManager.GetUriWithQueryParameters(
NavigationManager.ToAbsoluteUri(ResetPassword.PageUrl).AbsoluteUri,
new Dictionary<string, object?> { ["userId"] = userId, ["token"] = code });
await Sender.Publish(new ResetPasswordNotification(callbackUrl, toEmail, userName));
Logger.LogInformation("Rest password email sent to {0}.", toEmail);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,7 @@
<data name="Error: Invalid login attempt." xml:space="preserve">
<value>Error: intent d'inici de sessió no vàlid.</value>
</data>
<data name="Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps." xml:space="preserve">
<value>Error: el vostre compte no té permís per iniciar sessió. Assegureu-vos que el vostre compte s'hagi activat i que hàgiu completat tots els passos necessaris.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,7 @@
<data name="Error: Invalid login attempt." xml:space="preserve">
<value>Fehler: Ungültiger Anmeldeversuch.</value>
</data>
<data name="Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps." xml:space="preserve">
<value>Fehler: Ihr Konto darf sich nicht anmelden. Bitte stellen Sie sicher, dass Ihr Konto aktiviert wurde und Sie alle erforderlichen Schritte abgeschlossen haben.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,7 @@
<data name="Error: Invalid login attempt." xml:space="preserve">
<value>Error: Invalid login attempt.</value>
</data>
<data name="Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps." xml:space="preserve">
<value>Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,7 @@
<data name="Error: Invalid login attempt." xml:space="preserve">
<value>Error: intento de inicio de sesión no válido.</value>
</data>
<data name="Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps." xml:space="preserve">
<value>Error: Su cuenta no puede iniciar sesión. Asegúrese de que su cuenta haya sido activada y de haber completado todos los pasos requeridos.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,7 @@
<data name="Error: Invalid login attempt." xml:space="preserve">
<value>Erreur : tentative de connexion invalide.</value>
</data>
<data name="Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps." xml:space="preserve">
<value>Erreur : Votre compte n'est pas autorisé à se connecter. Veuillez vous assurer que votre compte a été activé et que vous avez effectué toutes les étapes requises.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,7 @@
<data name="Error: Invalid login attempt." xml:space="preserve">
<value>エラー: 無効なログイン試行です。</value>
</data>
<data name="Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps." xml:space="preserve">
<value>エラー: あなたのアカウントではログインが許可されていません。アカウントがアクティブ化されていて、必要な手順がすべて完了していることを確認してください。</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,7 @@
<data name="Error: Invalid login attempt." xml:space="preserve">
<value>កំហុស៖ ការព្យាយាមចូលមិនត្រឹមត្រូវ។</value>
</data>
<data name="Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps." xml:space="preserve">
<value>កំហុស៖ គណនីរបស់អ្នកមិនត្រូវបានអនុញ្ញាតឱ្យចូលទេ។ សូមប្រាកដថាគណនីរបស់អ្នកត្រូវបានធ្វើឱ្យសកម្ម ហើយអ្នកបានបញ្ចប់ជំហានដែលត្រូវការទាំងអស់។</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,7 @@
<data name="Error: Invalid login attempt." xml:space="preserve">
<value>오류: 잘못된 로그인 시도입니다.</value>
</data>
<data name="Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps." xml:space="preserve">
<value>오류: 귀하의 계정은 로그인이 허용되지 않습니다. 귀하의 계정이 활성화되었고 모든 필수 단계를 완료했는지 확인하십시오.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,7 @@
<data name="Error: Invalid login attempt." xml:space="preserve">
<value>Error: Invalid login attempt.</value>
</data>
<data name="Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps." xml:space="preserve">
<value>Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,7 @@
<data name="Error: Invalid login attempt." xml:space="preserve">
<value>Ошибка: Неверная попытка входа.</value>
</data>
<data name="Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps." xml:space="preserve">
<value>Ошибка: вашей учетной записи не разрешен вход в систему. Убедитесь, что ваша учетная запись активирована и вы выполнили все необходимые шаги.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,7 @@
<data name="Error: Invalid login attempt." xml:space="preserve">
<value>错误:登录尝试无效。</value>
</data>
<data name="Error: Your account is not allowed to log in. Please ensure your account has been activated and you have completed all required steps." xml:space="preserve">
<value>错误:您的帐户不允许登录。请确保您的帐户已激活并且您已完成所有必需的步骤。</value>
</data>
</root>

0 comments on commit e720a4d

Please sign in to comment.