production fixes;

unsuccessful login feedback, registration validateEmail message, end redirect, transfer price edit, other small fixes
This commit is contained in:
Adam 2024-08-23 17:20:24 +02:00
parent 4463be7507
commit 6294ffdb01
18 changed files with 273 additions and 53 deletions

View File

@ -28,7 +28,9 @@ public static class TiamConstClient
public static List<string> WelcomeEmailParameters = new List<string>()
{
"UserName",
"ActivationCode"
"SettingBaseUrl",
"UserId",
"Token"
};
public static List<string> ForgotPasswordEmailParameters = new List<string>()

View File

@ -117,5 +117,20 @@ namespace TIAM.Services.Server
return EmailTemplateHelper.ReplacePlaceholders(template, placeholders);
}
public static string GenerateWelcomeEmail(string userName, string settingBaseUrl, string userId, string token)
{
string template = EmailTemplateHelper.GetTemplate(TiamConstClient.WelcomeEmailTemplateName);
var placeholders = new Dictionary<string, string>
{
{ TiamConstClient.ForgotPasswordEmailParameters[0], userName },
{ TiamConstClient.ForgotPasswordEmailParameters[1], settingBaseUrl },
{ TiamConstClient.ForgotPasswordEmailParameters[2], userId },
{ TiamConstClient.ForgotPasswordEmailParameters[3], token }
};
return EmailTemplateHelper.ReplacePlaceholders(template, placeholders);
}
}
}

View File

@ -4,10 +4,10 @@
<title>Forgot password</title>
</head>
<body>
<p>Dear {{UserName}},</p>
<b>Dear {{UserName}},</b>
<p>Please follow the link below to renew your password:</p>
<p>
<p><a href="{{SettingBaseUrl}}/renewpassword/{{UserId}}/{{Token}}">Confirm Transfer</a></p>
<p><a href="{{SettingBaseUrl}}/renewpassword/{{UserId}}/{{Token}}">Renew password</a></p>
<p>If you did not request this, please disregard this email.</p>
<p>Thank you,<br />Tour I Am team</p>
</body>

View File

@ -4,7 +4,7 @@
<title>Welcome</title>
</head>
<body>
<h1>Hello, {{UserName}}!</h1>
<b>Hello, {{UserName}}!</b>
<p>You have received a message in the TourIam System: </p>
<p>{{MessageBody}}</p>
<hr/>

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<body>
<p>Dear {{UserName}},</p>
<b>Dear {{UserName}},</b>
<p>We are pleased to inform you that a transfer order has been placed. Below are the details of the transfer:</p>
<p>{{FromAddress}} - {{ToAddress}}</p>
<p>{{Appointment}}</p>

View File

@ -4,7 +4,7 @@
<title>Transfer modified</title>
</head>
<body>
<h1>Hello, {{UserName}}!</h1>
<b>Hello, {{UserName}}!</b>
<p>Your transfer has been modified.</p>
<p>You can check the details here: {{TransferUrl}}</p>
</body>

View File

@ -4,8 +4,9 @@
<title>Welcome</title>
</head>
<body>
<h1>Hello, {{UserName}}!</h1>
<b>Hello, {{UserName}}!</b>
<p>Thank you for joining us.</p>
<p>Your activation code is: {{ActivationCode}}</p>
<p><a href="{{SettingBaseUrl}}/validate/{{UserId}}/{{Token}}">Renew password</a></p>
<p>If you did not request this, please disregard this email.</p>
</body>
</html>

View File

@ -372,6 +372,18 @@ namespace TIAMMobileApp.Services
return result;
}
public async Task<bool> SendWelcomeMail(string emailAddress)
{
_logger.Info("SendWelcomeMail() called");
var url = $"{Setting.ApiBaseUrl}/{APIUrls.SendWelcomeMail}";
var response = await _http.PostAsJsonAsync(url, emailAddress);
var success = await response.Content.ReadFromJsonAsync<bool>();
_logger.Detail($"SendForgottenPasswordMail(): {success.ToString()}");
return success;
}
//public Task<Dictionary<int, string>> GetUserRolesAsync(UserModel userModel)
//{
// //TODO Finish this

View File

@ -163,11 +163,24 @@ else
<div class="d-flex justify-content-between align-items-center">
<h5 class="fw-normal mb-0"><a href="#!" class="text-decoration-none">Contact driver</a></h5>
<div class="vr"></div>
<h5 class="fw-normal mb-0"><a href="#!" class="text-decoration-none">Cancel</a></h5>
@{
if (_transfer.TransferStatusType != TransferStatusType.UserCanceled)
{
<h5 class="fw-normal mb-0"><DxButton RenderStyle="ButtonRenderStyle.Warning" Click="CancelTransfer">Cancel</DxButton></h5>
}
}
<div class="vr"></div>
@{
if(_transfer.Price != null || _transfer.Price != 0)
{
<DxButton RenderStyle="ButtonRenderStyle.Primary" Click="Pay">Pay</DxButton>
<div class="vr"></div>
<h5 class="fw-normal mb-0"><a class="btn btn-secondary" @onclick="SetEditMode">Modify</a></h5>
}
}
@*<h5 class="fw-normal mb-0"><a class="btn btn-secondary" @onclick="SetEditMode">Modify</a></h5>*@
<h5 class="fw-normal mb-0"><DxButton RenderStyle="ButtonRenderStyle.Secondary" Click="SetEditMode">Modify</DxButton></h5>
</div>
</div>
</div>
@ -369,6 +382,12 @@ else
}
private async Task CancelTransfer()
{
_transfer.TransferStatusType = TransferStatusType.UserCanceled;
var result = await UpdateTransfer(true);
}
private async Task Pay()
{
if (_transfer != null)
@ -436,6 +455,11 @@ else
}
}
}
else
{
//does a user exist with this userId?
await UserDataService.SetEmailConfirmed(transferUser.Id);
}
}
}
@ -497,7 +521,8 @@ else
{
try
{
var responseTransfer = await transferDataService.UpdateTransferAsync(_transfer);
// var responseTransfer = await transferDataService.UpdateTransferAsync(_transfer);
var responseTransfer = await _adminSignalRClient.PostDataAsync<Transfer>(SignalRTags.UpdateTransfer, _transfer);
if (responseTransfer != null)
{
return responseTransfer;

View File

@ -57,6 +57,7 @@
</div>
}
} *@
<p class="@messageClass">@resultMessage</p>
<div class="text-center fs-6">
No account yet? <a href="register">Sign up here!</a>
</div>

View File

@ -47,7 +47,8 @@ namespace TIAMSharedUI.Pages
public string TitleText { get; set; } = "dda,mnd,amn,a";
private int _currentStep = 1;
bool _loggedIn = false;
private string messageClass = "";
private string resultMessage = "";
private void GoToNextStep()
{
@ -80,8 +81,18 @@ namespace TIAMSharedUI.Pages
if (mainResponse != null)
{
//check for bad request
//TODO: fix hacky solution
if (!mainResponse.IsSuccess)
{
//await App.Current.MainPage.DisplayAlert("Error", "Invalid credentials", "Ok");
//display error message via jsinterop
BrowserConsoleLogWriter.Info("Invalid credentials");
messageClass = "text-danger";
resultMessage = "Invalid credentials";
await InvokeAsync(StateHasChanged);
//navManager.NavigateTo("login");
}
else
{
string authResponseJson = JsonSerializer.Serialize(mainResponse.Content);
var authResponse = JsonSerializer.Deserialize<AuthenticationResponse>(authResponseJson, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
@ -107,15 +118,6 @@ namespace TIAMSharedUI.Pages
await AuthStateProvider.GetAuthenticationStateAsync();
if (!mainResponse.IsSuccess)
{
//await App.Current.MainPage.DisplayAlert("Error", "Invalid credentials", "Ok");
//display error message via jsinterop
BrowserConsoleLogWriter.Info("Invalid credentials");
navManager.NavigateTo("login");
}
else
{
//await App.Current.MainPage.DisplayAlert("Success", "Successful login", "Ok");
//display success message via jsinterop
BrowserConsoleLogWriter.Info("Successful login");
@ -128,7 +130,8 @@ namespace TIAMSharedUI.Pages
return Task.CompletedTask;
}, user.UserId).Forget();
messageClass = "text-success";
resultMessage = "Successful login";
SaveToSessionInfo(user).Forget();
navManager.NavigateTo("/");

View File

@ -105,14 +105,13 @@
currentStep = 1;
var response = await UserDataservice.CreateUser(regModel);
LogToBrowserConsole("Registration started: " + "Email: " + regModel.Email + "PhoneNumber: " + regModel.PhoneNumber + "Password: " + regModel.Password);
if (response.isSuccess)
{
//await App.Current.MainPage.DisplayAlert("Error", "Invalid credentials", "Ok");
//display error message via jsinterop
LogToBrowserConsole(response.ErrorMessage);
var validateUser = await UserDataservice.SendWelcomeMail(regModel.Email!);
navManager.NavigateTo("/login");
}
else if (!response.isSuccess)

View File

@ -171,7 +171,7 @@
<DxFormLayoutItem Caption=@_localizer.GetString(ResourceKeys.PickupAddress) ColSpanMd="6">
@editFormContext.GetEditor("FromAddress")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Trip date:" ColSpanMd="6">
<DxFormLayoutItem Caption="Trip date:" ColSpanMd="3">
<DxDateEdit @bind-Date="@transfer2.Appointment"
TimeSectionVisible="true"
@ -179,17 +179,21 @@
</DxDateEdit>
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Passengers:" ColSpanMd="6">
<DxFormLayoutItem Caption="Passengers:" ColSpanMd="3">
@editFormContext.GetEditor("PassengerCount")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Paid:" ColSpanMd="6">
<DxFormLayoutItem Caption="Paid:" ColSpanMd="3">
@editFormContext.GetEditor("Payed")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Status:" ColSpanMd="6">
<DxFormLayoutItem Caption="Status:" ColSpanMd="3">
@editFormContext.GetEditor("TransferStatusType")
</DxFormLayoutItem>
<DxFormLayoutItem Caption="Price:" ColSpanMd="3">
@editFormContext.GetEditor("Price")
</DxFormLayoutItem>
</DxFormLayout>
</EditFormTemplate>

View File

@ -0,0 +1,85 @@
@page "/validate/{userId}/{renewToken}"
@inherits BasePageComponent
@using TIAM.Models.Dtos.Users
@using TIAM.Services
@using TIAMSharedUI.Shared.Components.BaseComponents
@using BlazorAnimation
@using TIAMWebApp.Shared.Application.Interfaces
@using TIAMWebApp.Shared.Application.Models.PageModels;
@using TIAMSharedUI.Pages.Components;
@using TIAMSharedUI.Pages.User.CardComponents
@using TIAMWebApp.Shared.Application.Services
@inject IUserDataService UserDataService
@inject AdminSignalRClient AdminSignalRClient
<PageTitle>Validate Email</PageTitle>
<div class="text-center m-5">
<h1>Validate email</h1>
<h2 style="font-size:small">Let's validate your email!</h2>
</div>
<div class="container mt-3">
<div class="row d-flex justify-content-center align-items-center h-100">
<div class="col-12 col-sm-6 px-5">
<Animation Effect="@Effect.FadeIn" Speed="@Speed.Slow" Delay="@TimeSpan.FromMilliseconds(250)">
<div class="card my-5">
<p>@resultMsg</p>
</div>
</Animation>
</div>
</div>
</div>
@code {
[Parameter] public string? userId { get; set; } = "";
[Parameter] public string? renewToken { get; set; } = "";
private bool isFormHidden = true;
string resultMsg = "";
private UserModelDtoDetail? user = new UserModelDtoDetail();
protected override async Task OnInitializedAsync()
{
if (userId != null && renewToken != null)
{
string msg = await UserDataService.ValidateForgotPasswordToken(Guid.Parse(userId), renewToken);
if (msg == "Success")
{
var result = await UserDataService.SetEmailConfirmed(Guid.Parse(userId));
if (result)
{
resultMsg = "Email validated, you can now login";
}
else
{
resultMsg = "Oops, something went wrong";
}
}
else
{
resultMsg = msg;
}
}
await base.OnInitializedAsync();
}
protected override async Task OnParametersSetAsync()
{
//validate Token
await base.OnParametersSetAsync();
}
}

View File

@ -379,6 +379,18 @@ namespace TIAMWebApp.Client.Services
return result;
}
public async Task<bool> SendWelcomeMail(string emailAddress)
{
_logger.Info("SendWelcomeMail() called");
var url = $"{Setting.ApiBaseUrl}/{APIUrls.SendWelcomeMail}";
var response = await _http.PostAsJsonAsync(url, emailAddress);
var success = await response.Content.ReadFromJsonAsync<bool>();
_logger.Detail($"SendForgottenPasswordMail(): {success.ToString()}");
return success;
}
/*public Task<Dictionary<int, string>> GetUserRolesAsync(UserModel userModel)
{
//TODO: finish this

View File

@ -479,7 +479,7 @@ namespace TIAMWebApp.Server.Controllers
message.Message.ContextId = user.Id;
message.Message.ContextType = MessageContextType.System;
message.Message.SenderId = Guid.Empty;
message.Message.Recipients.Add(new EmailRecipient(Guid.NewGuid(), user.Id, Guid.NewGuid(), email));
message.Message.Recipients.Add(new EmailRecipient(Guid.NewGuid(), user.Id, message.Message.Id, email));
message.Message.Text = EmailTemplateHelper.GenerateForgotPasswordEmail(
user.FullName,
@ -573,6 +573,62 @@ namespace TIAMWebApp.Server.Controllers
return false;
}
[AllowAnonymous]
[HttpPost]
[Route(APIUrls.SendWelcomeMailRouteName)]
public async Task<bool> SendWelcomeMail([FromBody] string email)
{
_logger.Info($"SendWelcomeMail called with id: {email}");
var user = await userDal.GetUserByEmailAsync(email, false);
if (user == null)
{
return false;
}
else
{
//create new token for the user
//user.ConfirmToken = Guid.NewGuid().ToString("N");
user.ConfirmToken = AcCharsGenerator.NewToken();
_logger.Debug($"Generated token for user: {user.ConfirmToken}");
var result = await adminDal.UpdateUserAsync(user);
_logger.Debug($"Saved token for user: {result.ConfirmToken}");
//send email
var message = new MessageSenderModel<EmailMessage>();
message.Message = new EmailMessage();
message.Message.EmailAddress = email;
message.Message.Id = Guid.NewGuid();
message.MessageType = MessageTypesEnum.email;
message.Message.Subject = "[Tour I Am] Validate your email";
message.Message.ContextId = user.Id;
message.Message.ContextType = MessageContextType.System;
message.Message.SenderId = Guid.Empty;
message.Message.Recipients.Add(new EmailRecipient(Guid.NewGuid(), user.Id, message.Message.Id, email));
message.Message.Text = EmailTemplateHelper.GenerateWelcomeEmail(
user.FullName,
Setting.BaseUrl,
user.Id.ToString(),
user.ConfirmToken);
_logger.Info(message.Message.Text);
var messageElement = message.Message;
Console.WriteLine(message.Message);
var mailResult = await messageSenderService.SendMessageAsync(messageElement, (int)message.MessageType);
await adminDal.AddEmailMessageAsync(messageElement);
_logger.Info("SendEmail result: " + mailResult);
//-----------------
if (mailResult == HttpStatusCode.OK.ToString())
{
await adminDal.AddEmailMessageAsync(messageElement);
return true;
}
else
{
return false;
}
}
}
}
}

View File

@ -32,5 +32,7 @@ namespace TIAMWebApp.Shared.Application.Interfaces
public Task<string> ValidateForgotPasswordToken(Guid userId, string token);
public Task<bool> SetEmailConfirmed(Guid userId);
public Task<bool> SendWelcomeMail(string emailAddress);
}
}

View File

@ -69,6 +69,9 @@ namespace TIAMWebApp.Shared.Application.Models
public const string SendForgottenPasswordMailRouteName = "SendForgottenPasswordMail";
public const string SendForgottenPasswordMail = UserAPI + SendForgottenPasswordMailRouteName;
public const string SendWelcomeMailRouteName = "SendWelcomeMail";
public const string SendWelcomeMail = UserAPI + SendWelcomeMailRouteName;
public const string ValidateForgottenPasswordTokenRouteName = "ValidateForgottenPasswordToken";
public const string ValidateForgottenPasswordToken = UserAPI + ValidateForgottenPasswordTokenRouteName;