From a7e8831ff9c94c463b93740b4ec31418d23655e5 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 5 Aug 2024 14:17:18 +0200 Subject: [PATCH 1/3] history fix --- .../CardComponents/ProductCardComponent.razor | 57 +++++++++---------- .../BaseComponents/UserBasePageComponent.cs | 4 +- 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/TIAMSharedUI/Pages/User/CardComponents/ProductCardComponent.razor b/TIAMSharedUI/Pages/User/CardComponents/ProductCardComponent.razor index 586cc402..e505c230 100644 --- a/TIAMSharedUI/Pages/User/CardComponents/ProductCardComponent.razor +++ b/TIAMSharedUI/Pages/User/CardComponents/ProductCardComponent.razor @@ -14,23 +14,20 @@ @using TIAMWebApp.Shared.Application.Models.PageModels @using TIAMWebApp.Shared.Application.Services @inject IServiceProviderDataService ServiceProviderDataService -@inject IUserDataService UserDataService; -@inject AdminSignalRClient AdminSignalRClient; -@inject IJSRuntime JsRuntime; -@inject NavigationManager NavManager; +@inject IUserDataService UserDataService +@inject AdminSignalRClient AdminSignalRClient +@inject IJSRuntime JsRuntime +@inject NavigationManager NavManager
- @*
- -
*@ - +
- - + +
+ Download QR
@@ -45,7 +42,6 @@

Information

- @RenderDetailsItem("fa-solid fa-user", "Contact Name", productProfile.FullName) @RenderDetailsItem("fa-solid fa-circle-info", "Description", Context.Description)
@@ -59,18 +55,12 @@

Use this link to send it in an email to the client

@_url - // Copy referral url - } } - -
-
- -
- +
+
@@ -89,15 +79,11 @@
@{ - if (!isAddressTransferDestination) { - //

Address:

- //

@(((Product)context.DataItem).Profile.Address.AddressText)

} } -
@@ -114,6 +100,15 @@ alert('Could not copy text: ' + err); }); } + + function downloadImage(base64String, filename) { + const link = document.createElement('a'); + link.href = base64String; + link.download = filename; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } @code { @@ -126,17 +121,21 @@ AccordionExpandCollapseAction ExpandCollapseAction { get; set; } = AccordionExpandCollapseAction.HeaderClick; private Profile productProfile = new Profile(); - private List destinations = []; + private List destinations = new List(); string msg; private bool isSaveActive = false; private bool isAddressTransferDestination = false; private async Task CopyUrl(string url) { - await JsRuntime.InvokeVoidAsync("copyToClipboard", url); } + private async Task DownloadImage() + { + await JsRuntime.InvokeVoidAsync("downloadImage", $"data:image/png;base64,{ImageSource}", "QRCode.jpg"); + } + protected override async Task OnInitializedAsync() { var productOwner = await AdminSignalRClient.GetByIdAsync>(SignalRTags.GetCompaniesById, Context.ServiceProviderId); @@ -158,7 +157,6 @@ protected override async Task OnParametersSetAsync() { - await base.OnParametersSetAsync(); } @@ -177,8 +175,6 @@ private bool CheckDestinations(Guid addressId) { - - if (destinations != null) { if (destinations.Any(d => d.AddressId == addressId)) @@ -194,7 +190,6 @@ { return false; } - } private async Task SaveAsDestination(Address address, Product product) @@ -212,7 +207,7 @@ } transferDestination.AddressId = address.Id; transferDestination.AddressString = address.AddressText; - var result = await AdminSignalRClient.PostDataAsync(SignalRTags.CreateTransferDestination, transferDestination); + var result = await AdminSignalRClient.PostDataAsync(SignalRTags.CreateTransferDestination, transferDestination); await InvokeAsync(StateHasChanged); } } diff --git a/TIAMSharedUI/Shared/Components/BaseComponents/UserBasePageComponent.cs b/TIAMSharedUI/Shared/Components/BaseComponents/UserBasePageComponent.cs index d6e07503..b3a52997 100644 --- a/TIAMSharedUI/Shared/Components/BaseComponents/UserBasePageComponent.cs +++ b/TIAMSharedUI/Shared/Components/BaseComponents/UserBasePageComponent.cs @@ -30,9 +30,7 @@ namespace TIAMSharedUI.Shared.Components.BaseComponents { base.OnInitialized(); _logger = new LoggerClient(_logWriters.ToArray()); - var currentUrl = _navManager.ToBaseRelativePath(_navManager.Uri); - _pageState.AddPageToHistory(currentUrl); - _logger.Debug(_pageState.GetGoBackPage()); + } } } From 1cbf88d563acbfdf0d588a3b325505285082d7bc Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 8 Aug 2024 20:16:14 +0200 Subject: [PATCH 2/3] WIP renew password, email template handling and usage --- TIAM.Core/Consts/TiamConst.cs | 45 +++++- TIAM.Services.Server/EmailTemplateHelper.cs | 106 ++++++++++++++ .../ForgotPasswordEmailTemplate.html | 14 ++ .../NewTransferEmailTemplate.html | 16 +++ .../TransferModifiedEmailTemplate.html | 11 ++ .../EmailTemplates/WelcomeEmailTemplate.html | 11 ++ TIAM.Services.Server/MessageSenderService.cs | 64 +++++++-- .../TIAM.Services.Server.csproj | 25 ++++ .../Services/UserDataServiceMobile.cs | 33 +++++ .../Pages/Components/LoginStep1.razor | 6 +- TIAMSharedUI/Pages/ForgottenPassword.razor | 91 ++++++++++++ TIAMSharedUI/Pages/Login.razor | 2 +- TIAMSharedUI/Pages/RenewPassword.razor | 115 ++++++++++++--- .../CardComponents/UserCardComponent.razor | 11 +- .../Client/Services/UserDataServiceWeb.cs | 28 ++++ .../Server/Controllers/UserAPIController.cs | 132 ++++++++++++++++-- .../Shared/Interfaces/IUserDataService.cs | 4 + TIAMWebApp/Shared/Models/APIUrls.cs | 6 + 18 files changed, 661 insertions(+), 59 deletions(-) create mode 100644 TIAM.Services.Server/EmailTemplateHelper.cs create mode 100644 TIAM.Services.Server/EmbeddedResources/EmailTemplates/ForgotPasswordEmailTemplate.html create mode 100644 TIAM.Services.Server/EmbeddedResources/EmailTemplates/NewTransferEmailTemplate.html create mode 100644 TIAM.Services.Server/EmbeddedResources/EmailTemplates/TransferModifiedEmailTemplate.html create mode 100644 TIAM.Services.Server/EmbeddedResources/EmailTemplates/WelcomeEmailTemplate.html create mode 100644 TIAMSharedUI/Pages/ForgottenPassword.razor diff --git a/TIAM.Core/Consts/TiamConst.cs b/TIAM.Core/Consts/TiamConst.cs index 9fe65d79..1b1bf04a 100644 --- a/TIAM.Core/Consts/TiamConst.cs +++ b/TIAM.Core/Consts/TiamConst.cs @@ -6,17 +6,58 @@ namespace TIAM.Core.Consts; public static class TiamConstClient { public static Guid TransferProductId = Guid.Parse("814b5495-c2e9-4f1d-a73f-37cd5d353078"); - public static Guid[] DevAdminIds = new Guid[2]{Guid.Parse("dcf451d2-cc4c-4ac2-8c1f-da00041be1fd"), Guid.Parse("4cbaed43-2465-4d99-84f1-c8bc6b7025f7") }; + public static Guid[] DevAdminIds = new Guid[2] { Guid.Parse("dcf451d2-cc4c-4ac2-8c1f-da00041be1fd"), Guid.Parse("4cbaed43-2465-4d99-84f1-c8bc6b7025f7") }; public static Guid[] SysAdmins = new Guid[3] { Guid.Parse("dcf451d2-cc4c-4ac2-8c1f-da00041be1fd"), Guid.Parse("4cbaed43-2465-4d99-84f1-c8bc6b7025f7"), Guid.Parse("540271f6-c604-4c16-8160-d5a7cafedf00") }; - public static string SystemEmailAddress = "system@touriam.com"; + public static Dictionary SysAccounts = new Dictionary + { + { "SystemEmailSender", Guid.Parse("5e13e051-4fd6-4a30-a371-75cc785cfb84")}, + }; + + public static string WelcomeEmailTemplateName = "WelcomeEmailTemplate"; + public static string NewTransferEmailTemplateName = "NewTransferEmailTemplate"; + public static string TransferModifiedEmailTemplateName = "TramsferModifiedEmailTemplate"; + public static string ForgotPasswordEmailTemplateName = "ForgotPasswordEmailTemplate"; + + public static List WelcomeEmailParameters = new List() + { + "UserName", + "ActivationCode" + }; + + public static List ForgotPasswordEmailParameters = new List() + { + //string userName, string settingBaseUrl, string userId, string token + "UserName", + "SettingBaseUrl", + "UserId", + "Token" + }; + + public static List NewTransferEmailParameters = new List() + { + //string userName, string fromAddress, string toAddress, string appointment, + //string fullname,string passengerCount, string luggageCount, string settingBaseUrl, string transferId + "UserName", + "FromAddress", + "ToAddress", + "Appointment", + "FullName", + "PassengerCount", + "LuggageCount", + "SettingBaseUrl", + "TransferId" + }; + #if RELEASE +public static string SystemEmailAddress = "system@touriam.com"; public static LogLevel DefaultLogLevelClient = LogLevel.Debug; #else + public static string SystemEmailAddress = "system@anataworld.com"; public static LogLevel DefaultLogLevelClient = LogLevel.Detail; #endif } diff --git a/TIAM.Services.Server/EmailTemplateHelper.cs b/TIAM.Services.Server/EmailTemplateHelper.cs new file mode 100644 index 00000000..bb5e48c9 --- /dev/null +++ b/TIAM.Services.Server/EmailTemplateHelper.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using TIAM.Core.Consts; + +namespace TIAM.Services.Server +{ + + public static class EmailTemplateHelper + { + public static string GetTemplate(string templateName) + { + var assembly = Assembly.GetExecutingAssembly(); + var resourceName = $"TIAM.Services.Server.EmbeddedResources.EmailTemplates.{templateName}.html"; + Console.WriteLine(resourceName); + if (assembly.GetManifestResourceStream(resourceName) != null) + { + + using (Stream stream = assembly.GetManifestResourceStream(resourceName)) + { + if (stream != null) + { + using (StreamReader reader = new StreamReader(stream)) + { + return reader.ReadToEnd(); + } + } + else + { + return "File not found"; + } + } + } + else + { + return "Error"; + } + } + + public static string ReplacePlaceholders(string template, IDictionary placeholders) + { + foreach (var placeholder in placeholders) + { + template = template.Replace($"{{{{{placeholder.Key}}}}}", placeholder.Value); + } + return template; + } + + public static string GenerateForgotPasswordEmail(string userName, string settingBaseUrl, string userId, string token) + { + string template = EmailTemplateHelper.GetTemplate(TiamConstClient.ForgotPasswordEmailTemplateName); + + var placeholders = new Dictionary + { + { TiamConstClient.ForgotPasswordEmailParameters[0], userName }, + { TiamConstClient.ForgotPasswordEmailParameters[1], settingBaseUrl }, + { TiamConstClient.ForgotPasswordEmailParameters[2], userId }, + { TiamConstClient.ForgotPasswordEmailParameters[3], token } + }; + + return EmailTemplateHelper.ReplacePlaceholders(template, placeholders); + } + + public static string GenerateNewTransferEmail(string userName, string fromAddress, string toAddress, string appointment, string fullName, string passengerCount, string luggageCount, string settingBaseUrl, string transferId) + { + string template = EmailTemplateHelper.GetTemplate(TiamConstClient.ForgotPasswordEmailTemplateName); + + var placeholders = new Dictionary + { + { TiamConstClient.NewTransferEmailParameters[0], userName }, + { TiamConstClient.NewTransferEmailParameters[1], fromAddress }, + { TiamConstClient.NewTransferEmailParameters[2], toAddress }, + { TiamConstClient.NewTransferEmailParameters[3], appointment }, + { TiamConstClient.NewTransferEmailParameters[4], fullName }, + { TiamConstClient.NewTransferEmailParameters[5], passengerCount }, + { TiamConstClient.NewTransferEmailParameters[6], luggageCount }, + { TiamConstClient.NewTransferEmailParameters[7], settingBaseUrl }, + { TiamConstClient.NewTransferEmailParameters[7], transferId } + }; + + return EmailTemplateHelper.ReplacePlaceholders(template, placeholders); + } + + public static string GenerateTransferModifiedEmail(string userName, string fromAddress, string toAddress, string appointment, string fullName, string passengerCount, string luggageCount, string settingBaseUrl, string transferId) + { + string template = EmailTemplateHelper.GetTemplate(TiamConstClient.ForgotPasswordEmailTemplateName); + + var placeholders = new Dictionary + { + { TiamConstClient.NewTransferEmailParameters[0], userName }, + { TiamConstClient.NewTransferEmailParameters[1], fromAddress }, + { TiamConstClient.NewTransferEmailParameters[2], toAddress }, + { TiamConstClient.NewTransferEmailParameters[3], appointment }, + { TiamConstClient.NewTransferEmailParameters[4], fullName }, + { TiamConstClient.NewTransferEmailParameters[5], passengerCount }, + { TiamConstClient.NewTransferEmailParameters[6], luggageCount }, + { TiamConstClient.NewTransferEmailParameters[7], settingBaseUrl }, + { TiamConstClient.NewTransferEmailParameters[7], transferId } + }; + + return EmailTemplateHelper.ReplacePlaceholders(template, placeholders); + } + + } +} diff --git a/TIAM.Services.Server/EmbeddedResources/EmailTemplates/ForgotPasswordEmailTemplate.html b/TIAM.Services.Server/EmbeddedResources/EmailTemplates/ForgotPasswordEmailTemplate.html new file mode 100644 index 00000000..64c43a24 --- /dev/null +++ b/TIAM.Services.Server/EmbeddedResources/EmailTemplates/ForgotPasswordEmailTemplate.html @@ -0,0 +1,14 @@ + + + + Forgot password + + +

Dear {{UserName}},

+

Please follow the link below to renew your password:

+

+

Confirm Transfer

+

If you did not request this, please disregard this email.

+

Thank you,
Tour I Am team

+ + \ No newline at end of file diff --git a/TIAM.Services.Server/EmbeddedResources/EmailTemplates/NewTransferEmailTemplate.html b/TIAM.Services.Server/EmbeddedResources/EmailTemplates/NewTransferEmailTemplate.html new file mode 100644 index 00000000..ed750c67 --- /dev/null +++ b/TIAM.Services.Server/EmbeddedResources/EmailTemplates/NewTransferEmailTemplate.html @@ -0,0 +1,16 @@ + + + +

Dear {{UserName}},

+

We are pleased to inform you that a transfer order has been placed. Below are the details of the transfer:

+

{{FromAddress}} - {{ToAddress}}

+

{{Appointment}}

+

{{FullName}}

+

{{PassengerCount}}

+

{{LuggageCount}}

+

Please confirm the transfer by clicking on the following link:

+

Confirm Transfer

+

If you did not request this transfer, please disregard this email.

+

Thank you,
Tour I Am team

+ + \ No newline at end of file diff --git a/TIAM.Services.Server/EmbeddedResources/EmailTemplates/TransferModifiedEmailTemplate.html b/TIAM.Services.Server/EmbeddedResources/EmailTemplates/TransferModifiedEmailTemplate.html new file mode 100644 index 00000000..d035e8c3 --- /dev/null +++ b/TIAM.Services.Server/EmbeddedResources/EmailTemplates/TransferModifiedEmailTemplate.html @@ -0,0 +1,11 @@ + + + + Transfer modified + + +

Hello, {{UserName}}!

+

Your transfer has been modified.

+

You can check the details here: {{TransferUrl}}

+ + \ No newline at end of file diff --git a/TIAM.Services.Server/EmbeddedResources/EmailTemplates/WelcomeEmailTemplate.html b/TIAM.Services.Server/EmbeddedResources/EmailTemplates/WelcomeEmailTemplate.html new file mode 100644 index 00000000..b39fe651 --- /dev/null +++ b/TIAM.Services.Server/EmbeddedResources/EmailTemplates/WelcomeEmailTemplate.html @@ -0,0 +1,11 @@ + + + + Welcome + + +

Hello, {{UserName}}!

+

Thank you for joining us.

+

Your activation code is: {{ActivationCode}}

+ + \ No newline at end of file diff --git a/TIAM.Services.Server/MessageSenderService.cs b/TIAM.Services.Server/MessageSenderService.cs index 9df20132..2ab3b18e 100644 --- a/TIAM.Services.Server/MessageSenderService.cs +++ b/TIAM.Services.Server/MessageSenderService.cs @@ -4,8 +4,10 @@ using AyCode.Models.Enums; using Microsoft.Extensions.Configuration; using SendGrid; using SendGrid.Helpers.Mail; +using TIAM.Core.Consts; using TIAM.Database.DataLayers.Admins; using TIAM.Entities.Emails; +using TIAM.Entities.Users; namespace TIAM.Services.Server { @@ -20,7 +22,7 @@ namespace TIAM.Services.Server Console.WriteLine($@"EmailMessage!!!"); // Access DerivedClass properties //var subject = emailMessage.Subject; - + //adminDal.AddEmailMessageAsync(message).Forget(); result = (await SendMailWithSendgrid(message)).ToString(); //?? HttpStatusCode.BadRequest.ToString(); break; @@ -46,24 +48,41 @@ namespace TIAM.Services.Server Console.WriteLine($@"Message: {message.Text}"); //resolve user!!! - if (!message.SenderId.HasValue) return HttpStatusCode.BadRequest; + User senderUser; - var senderUser = adminDal.GetUserById(message.SenderId.Value); - - if (senderUser == null) return HttpStatusCode.BadRequest; - var apiKey = configuration["SendGrid:Key"]; var client = new SendGridClient(apiKey); EmailAddress from; - - if (message.SenderId == Guid.Empty) + if (!message.SenderId.HasValue) { - message.EmailAddress = "noreply@anataworld.com"; - from = new EmailAddress("noreply@anataworld.com", "TourIAm mailservice"); + //SYSTEM MAIL + message.SenderId = TiamConstClient.SysAccounts.FirstOrDefault(x => x.Key == "SystemEmailSender").Value; + senderUser = null; //TODO get user from DB soon } else { - from = new EmailAddress(message.EmailAddress, senderUser.Profile.Name); + //USER sent message + senderUser = adminDal.GetUserById(message.SenderId.Value); + } + + + if (senderUser == null) + { + + if (message.SenderId == Guid.Empty) + { + message.EmailAddress = TiamConstClient.SystemEmailAddress; + from = new EmailAddress(TiamConstClient.SystemEmailAddress, "TourIAm mailservice"); + } + else + { + //user not valid, don't send message + return HttpStatusCode.BadRequest; + } + } + else + { + from = new EmailAddress(TiamConstClient.SystemEmailAddress, senderUser.Profile.Name); } Response[] responses = []; @@ -93,9 +112,9 @@ namespace TIAM.Services.Server //message.Id = Guid.NewGuid(); //adminDal.AddEmailMessageAsync(message).Forget(); } - catch(Exception ex) - { - Console.WriteLine(ex.ToString() ); + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); } if (responses.Any(response => !response.IsSuccessStatusCode)) @@ -136,8 +155,23 @@ namespace TIAM.Services.Server // return HttpStatusCode.OK; //} ////return response.StatusCode; - + } + public string GenerateWelcomeEmail(string userName, string activationCode) + { + string template = EmailTemplateHelper.GetTemplate(TiamConstClient.WelcomeEmailTemplateName); + + var placeholders = new Dictionary + { + { "UserName", userName }, + { "ActivationCode", activationCode } + }; + + return EmailTemplateHelper.ReplacePlaceholders(template, placeholders); + } + + + } } diff --git a/TIAM.Services.Server/TIAM.Services.Server.csproj b/TIAM.Services.Server/TIAM.Services.Server.csproj index f429caa5..feb967b2 100644 --- a/TIAM.Services.Server/TIAM.Services.Server.csproj +++ b/TIAM.Services.Server/TIAM.Services.Server.csproj @@ -6,6 +6,25 @@ enable + + + + + + + + + + Always + + + Always + + + Always + + + @@ -64,4 +83,10 @@ + + + Always + + + diff --git a/TIAMMobileApp/Services/UserDataServiceMobile.cs b/TIAMMobileApp/Services/UserDataServiceMobile.cs index 3cf7a49f..0de804e9 100644 --- a/TIAMMobileApp/Services/UserDataServiceMobile.cs +++ b/TIAMMobileApp/Services/UserDataServiceMobile.cs @@ -324,6 +324,39 @@ namespace TIAMMobileApp.Services return result; } + public async Task SendForgottenPasswordMail(string emailAddress) + { + _logger.Info("SendForgottenPasswordMail() called"); + + var url = $"{Setting.ApiBaseUrl}/{APIUrls.SendForgottenPasswordMail}"; + var response = await http.PostAsJsonAsync(url, emailAddress); + var success = await response.Content.ReadFromJsonAsync(); + _logger.Detail($"SendForgottenPasswordMail(): {success.ToString()}"); + return success; + } + + public async Task ValidateForgotPasswordToken(Guid userId, string token) + { + _logger.Info("SendForgottenPasswordMail() called"); + + string[] parameters = new string[2]; + parameters[0] = userId.ToString(); + parameters[1] = token.ToString(); + + var url = $"{Setting.ApiBaseUrl}/{APIUrls.SendForgottenPasswordMail}"; + + var response = await http.PostAsJsonAsync(url, parameters); + var success = await response.Content.ReadFromJsonAsync(); + + if (success == "Success") + { + _logger.Detail($"SendForgottenPasswordMail(): {success}"); + } + + return success; + + } + //public Task> GetUserRolesAsync(UserModel userModel) //{ // //TODO Finish this diff --git a/TIAMSharedUI/Pages/Components/LoginStep1.razor b/TIAMSharedUI/Pages/Components/LoginStep1.razor index db04bf5c..c9731143 100644 --- a/TIAMSharedUI/Pages/Components/LoginStep1.razor +++ b/TIAMSharedUI/Pages/Components/LoginStep1.razor @@ -1,4 +1,6 @@ -@using TIAMWebApp.Shared.Application.Models.PageModels; +@using AyCode.Core.Consts +@using TIAM.Core.Consts +@using TIAMWebApp.Shared.Application.Models.PageModels; @* *@ @@ -44,7 +46,7 @@ IEnumerable PredefinedPlaceholders { get; set; } = new List() { '_', '#' }; - string EmailMask { get; set; } = @"(\w|[.-])+@(\w|-)+\.(\w|-){2,4}"; + string EmailMask { get; set; } = AcRegExpression.EmailMask; MaskAutoCompleteMode AutoCompleteMode { get; set; } = MaskAutoCompleteMode.Strong; char Placeholder { get; set; } = '_'; bool PlaceholderVisible { get; set; } = false; diff --git a/TIAMSharedUI/Pages/ForgottenPassword.razor b/TIAMSharedUI/Pages/ForgottenPassword.razor new file mode 100644 index 00000000..92dd2e7b --- /dev/null +++ b/TIAMSharedUI/Pages/ForgottenPassword.razor @@ -0,0 +1,91 @@ +@page "/forgotpassword" +@inherits BasePageComponent +@using AyCode.Core.Consts +@using AyCode.Core.Helpers +@using TIAM.Models.Dtos.Users +@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 AdminSignalRClient AdminSignalRClient +@inject IUserDataService UserDataService + +Forgot password + +
+

Renew password

+

Good to see you again!

+
+ + +
+
+
+ +
+ +
+ +
+ @_localizer["LoginTitleText"] +
+ + + + Send +
+ No account yet? Sign up here! +
+
+ Figured it out? Back to login! +
+
+
+
+
+
+ +

+ @msg; + + +

+
+
+
+
+ +@code { + + private string emailAddress { get; set; } + string EmailMask { get; set; } = AcRegExpression.EmailMask; + MaskAutoCompleteMode AutoCompleteMode { get; set; } = MaskAutoCompleteMode.Strong; + char Placeholder { get; set; } = '_'; + bool PlaceholderVisible { get; set; } = false; + + private bool sendResult = false; + private string msg = "Welcome back to TourIam! We're delighted to have you return to our platform. Let's figure out your password issue! Please fill in the email address you have used for registration."; + + protected override async Task OnInitializedAsync() + { + + await base.OnInitializedAsync(); + } + + private void SendMail(string email) + { + var sendResult = UserDataService.SendForgottenPasswordMail(emailAddress).Forget; + + } +} diff --git a/TIAMSharedUI/Pages/Login.razor b/TIAMSharedUI/Pages/Login.razor index 444195fe..7fb35076 100644 --- a/TIAMSharedUI/Pages/Login.razor +++ b/TIAMSharedUI/Pages/Login.razor @@ -61,7 +61,7 @@ No account yet? Sign up here!
- Forgot your password? Click here! + Forgot your password? Click here!
diff --git a/TIAMSharedUI/Pages/RenewPassword.razor b/TIAMSharedUI/Pages/RenewPassword.razor index 398ae647..24552f95 100644 --- a/TIAMSharedUI/Pages/RenewPassword.razor +++ b/TIAMSharedUI/Pages/RenewPassword.razor @@ -1,13 +1,18 @@ -@page "/renewpassword" +@page "/renewpassword/{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 -Forgot password +Renew password

Renew password

@@ -20,22 +25,47 @@
+ @{ + if (!isFormHidden) + { +
+ +
+ @_localizer["LoginTitleText"] +
+ +
+ No account yet? Sign up here! +
+
+ Figured it out? Back to login! +
+
+ } + + else + { +
+ +
+ @_localizer["LoginTitleText"] +
+

@resultMsg

+
+ No account yet? Sign up here! +
+
+ Figured it out? Back to login! +
+
+ } + } + -
- -
- @_localizer["LoginTitleText"] -
- -
- No account yet? Sign up here! -
-
- Figured it out? Back to login! -
-
@@ -52,13 +82,54 @@
@code { + [Parameter] public string? userId { get; set; } = ""; + [Parameter] public string? renewToken { get; set; } = ""; - [Parameter] public string renewToken { get; set; } - [Parameter] public string emailAddress { get; set; } + private bool isFormHidden = true; + string resultMsg = ""; + private UserModelDtoDetail? user = new UserModelDtoDetail(); - private UserModelDtoDetail user; - protected override Task OnInitializedAsync() + protected override async Task OnInitializedAsync() { - return base.OnInitializedAsync(); + + if (userId != null && renewToken != null) + { + string msg = await UserDataService.ValidateForgotPasswordToken(Guid.Parse(userId), renewToken); + if (msg == "Success") + { + user = await UserDataService.GetUserDetailByIdAsync(Guid.Parse(userId)); + isFormHidden = false; + } + else + { + isFormHidden = true; + resultMsg = msg; + } + } + await base.OnInitializedAsync(); } + + protected override async Task OnParametersSetAsync() + { + + + //validate Token + + await base.OnParametersSetAsync(); + } + + private void SendForm(bool isSuccess) + { + if (isSuccess) + { + resultMsg = "Successful, now you can go to the login page and log in with your new password!"; + } + else + { + resultMsg = "Password wasn't saved. Please try again sending the forgotten password email. "; + } + } + + + } diff --git a/TIAMSharedUI/Pages/User/CardComponents/UserCardComponent.razor b/TIAMSharedUI/Pages/User/CardComponents/UserCardComponent.razor index bb83c270..71dc731a 100644 --- a/TIAMSharedUI/Pages/User/CardComponents/UserCardComponent.razor +++ b/TIAMSharedUI/Pages/User/CardComponents/UserCardComponent.razor @@ -62,7 +62,7 @@ @code { [Parameter] public UserModelDtoDetail Context { get; set; } - [Parameter] public EventCallback DataChanged { get; set; } + [Parameter] public EventCallback DataChanged { get; set; } [Parameter] public bool IsForgotten { get; set; } = false; @@ -126,9 +126,9 @@ protected async Task SetPassword() { + bool isSuccess = false; if (!IsForgotten) { - isSaveActive = false; var changePasswordDto = new ChangePasswordDto(Context.Id, OldPassword, NewPassword); @@ -148,26 +148,25 @@ else { isSaveActive = false; - var forgotPasswordDto = new ForgotPasswordDto(Context.UserDto.EmailAddress, NewPassword); //var changePasswordDto = new ChangePasswordDto(Context.Id, "Asdasd123456", NewPassword); var result = await AdminSignalRClient.PostDataAsync(SignalRTags.UserForgotPassword, forgotPasswordDto); if (result != null) { + isSuccess = true; msg = $"Password saved"; StateHasChanged(); } else { + isSuccess = false; msg = "Some error occured during saving, please try again later"; } } - await DataChanged.InvokeAsync(msg); + await DataChanged.InvokeAsync(isSuccess); } - - protected override async Task OnInitializedAsync() { diff --git a/TIAMWebApp/Client/Services/UserDataServiceWeb.cs b/TIAMWebApp/Client/Services/UserDataServiceWeb.cs index 3bccb2fb..c7f5ba39 100644 --- a/TIAMWebApp/Client/Services/UserDataServiceWeb.cs +++ b/TIAMWebApp/Client/Services/UserDataServiceWeb.cs @@ -331,6 +331,34 @@ namespace TIAMWebApp.Client.Services return result; } + public async Task SendForgottenPasswordMail(string emailAddress) + { + _logger.Info("SendForgottenPasswordMail() called"); + + var url = $"{Setting.ApiBaseUrl}/{APIUrls.SendForgottenPasswordMail}"; + var response = await http.PostAsJsonAsync(url, emailAddress); + var success = await response.Content.ReadFromJsonAsync(); + + _logger.Detail($"SendForgottenPasswordMail(): {success.ToString()}"); + return success; + } + + public async Task ValidateForgotPasswordToken(Guid userId, string token) + { + string? result = ""; + _logger.Info("ValidateForgotPasswordToken() called"); + + var url = $"{Setting.ApiBaseUrl}/{APIUrls.ValidateForgottenPasswordToken}"; + var parameters = new[] { userId.ToString(), token }; + + var response = await http.PostAsJsonAsync(url, parameters); + result = await response.Content.ReadAsStringAsync(); + + _logger.Detail($"ValidateForgotPasswordToken(): {result}"); + + return result; + } + /*public Task> GetUserRolesAsync(UserModel userModel) { //TODO: finish this diff --git a/TIAMWebApp/Server/Controllers/UserAPIController.cs b/TIAMWebApp/Server/Controllers/UserAPIController.cs index c78f519a..8188e189 100644 --- a/TIAMWebApp/Server/Controllers/UserAPIController.cs +++ b/TIAMWebApp/Server/Controllers/UserAPIController.cs @@ -24,16 +24,22 @@ using TIAM.Services; using TIAM.Services.Interfaces; using TIAMWebApp.Shared.Application.Services; using GoogleApi.Entities.Search.Video.Common; +using TIAM.Database.DataLayers.Admins; +using TIAM.Entities.Emails; +using TIAMWebApp.Shared.Application.Models.ClientSide.Messages; +using TIAMWebApp.Shared.Application.Models.ClientSide; +using System.Net; +using TIAM.Services.Server; namespace TIAMWebApp.Server.Controllers { [Authorize] [ApiController] [Route("api/v1/[controller]")] - public class UserAPIController(IConfiguration configuration, UserDal userDal, IEnumerable logWriters) : ControllerBase, IUserApiControllerCommon + public class UserAPIController(IConfiguration configuration, AdminDal adminDal, UserDal userDal, IMessageSenderService messageSenderService, IEnumerable logWriters) : ControllerBase, IUserApiControllerCommon { private readonly TIAM.Core.Loggers.Logger _logger = new(logWriters.ToArray()); - + private LoginService _loginService = new LoginService(userDal, configuration); //private readonly IWebHostEnvironment _webHostEnvironment; //readonly PasswordHasher _hasher = new(); @@ -61,7 +67,7 @@ namespace TIAMWebApp.Server.Controllers // //logItem.LogHeaderId = ??? // logItem.TimeStampUtc = DateTime.UtcNow; - + // _logger.Write(logItem); // //_logger.Writer()?.Write(logItem.AppType, logItem.LogLevel, logItem.Text, logItem.CallerName, logItem.CategoryName, logItem.ErrorType, logItem.Exception); @@ -263,8 +269,8 @@ namespace TIAMWebApp.Server.Controllers var userId = Guid.NewGuid(); var email = user.Email?.ToLower(); var phoneNumber = user.PhoneNumber; - var password = user.Password; - + var password = user.Password; + var referralId = user.ReferralId.IsNullOrEmpty() ? null : user.ReferralId; if (email is null || phoneNumber is null || password is null) @@ -288,7 +294,7 @@ namespace TIAMWebApp.Server.Controllers } return Ok(guestUser); - } + } [AllowAnonymous] [HttpGet] @@ -375,7 +381,7 @@ namespace TIAMWebApp.Server.Controllers public async Task UpdateUserModelDtoDetail(UserModelDtoDetail userModelDtoDetail) { _logger.Info($"UpdateUserModelDtoDetail called; Id: {userModelDtoDetail.UserDto.Id}"); - + var result = await userDal.UpdateUserModelDtoDetailAsync(userModelDtoDetail); return result; } @@ -400,9 +406,9 @@ namespace TIAMWebApp.Server.Controllers throw new NotImplementedException("Profile, Address, etc..."); if (userModelDtoDetail.UserDto.Id.IsNullOrEmpty()) userModelDtoDetail.UserDto.Id = Guid.NewGuid(); - + _logger.Info($"AddUserModelDtoDetail called; Id: {userModelDtoDetail.UserDto.Id}"); - + var result = await userDal.AddUserModelDtoDetailAsync(userModelDtoDetail); return result; } @@ -412,7 +418,7 @@ namespace TIAMWebApp.Server.Controllers [Route(APIUrls.GetUserByEmailRouteName + "/{email}")] public async Task? GetUserByEmail(string email) { - _logger.Info($"GetUserByEmail called with email: {email}"); + _logger.Info($"GetUserByEmail called with email: {email}"); var result = await userDal.GetUserModelDtoByEmailAsync(email, false); if (result == null) { @@ -441,8 +447,112 @@ namespace TIAMWebApp.Server.Controllers public async Task GetUserDetailById([FromBody] Guid id) { _logger.Info($"GetUserDetailById called with id: {id}"); - var result = await userDal.GetUserModelDtoByIdAsync(id, true); + var result = await userDal.GetUserModelDtoByIdAsync(id, false); return result; } + + [AllowAnonymous] + [HttpPost] + [Route(APIUrls.SendForgottenPasswordMailRouteName)] + public async Task SendForgottenPasswordMail([FromBody] string email) + { + User user; + _logger.Info($"SendForgottenPasswordMail called with id: {email}"); + 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 + + _logger.Info($"Created transfer, send emailMessage!!!"); + var message = new MessageSenderModel(); + message.Message = new EmailMessage(); + message.Message.EmailAddress = email; + message.Message.Id = Guid.NewGuid(); + message.MessageType = AyCode.Models.Enums.MessageTypesEnum.email; + message.Message.Subject = "[Tour I Am] New transfer in Budapest"; + message.Message.ContextId = user.Id; + message.Message.SenderId = Guid.Empty; + message.Message.Recipients.Add(new EmailRecipient(Guid.NewGuid(), user.Id, Guid.NewGuid(), email)); + //string FormatEmailContent() + //{ + // return $@" + // + // + //

Dear {user.Profile.FirstName},

+ //

Please follow the link below to renew your password:

+ //

+ //

Confirm Transfer

+ //

If you did not request this, please disregard this email.

+ //

Thank you,
Tour I Am team

+ // + // "; + //} + //message.Message.Text = FormatEmailContent(); + message.Message.Text = EmailTemplateHelper.GenerateForgotPasswordEmail(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; + } + } + } + + [AllowAnonymous] + [HttpPost] + [Route(APIUrls.ValidateForgottenPasswordTokenRouteName)] + public async Task ValidateForgottenPasswordToken([FromBody] string[] parameters) + { + User? user; + _logger.Info($"ValidateForgottenPasswordToken called with id: {parameters[0]}"); + if(parameters != null && parameters[0] != null && parameters[1] != null) + { + user = await userDal.GetUserByIdAsync(Guid.Parse(parameters[0]), false); + if (user == null) + { + return "User not found"; + } + else + { + if (parameters[1] == user.ConfirmToken) + { + _logger.Debug($"Generated token for user: {user.ConfirmToken}"); + return "Success"; + + } + else + { + _logger.Debug($"Generated token for user: {user.ConfirmToken}"); + return "Invalid token"; + } + + } + } + else + { + return "Invalid request"; + } + + } } } \ No newline at end of file diff --git a/TIAMWebApp/Shared/Interfaces/IUserDataService.cs b/TIAMWebApp/Shared/Interfaces/IUserDataService.cs index 99e29458..8e015cc1 100644 --- a/TIAMWebApp/Shared/Interfaces/IUserDataService.cs +++ b/TIAMWebApp/Shared/Interfaces/IUserDataService.cs @@ -26,5 +26,9 @@ namespace TIAMWebApp.Shared.Application.Interfaces Task RefreshToken(); public Task Logout(string refreshToken); + + public Task SendForgottenPasswordMail(string emailAddress); + + public Task ValidateForgotPasswordToken(Guid userId, string token); } } \ No newline at end of file diff --git a/TIAMWebApp/Shared/Models/APIUrls.cs b/TIAMWebApp/Shared/Models/APIUrls.cs index 5e35471c..3a7fac31 100644 --- a/TIAMWebApp/Shared/Models/APIUrls.cs +++ b/TIAMWebApp/Shared/Models/APIUrls.cs @@ -66,6 +66,12 @@ namespace TIAMWebApp.Shared.Application.Models public const string RefreshTokenRouteName = "RefreshToken"; public const string RefreshToken = UserAPI + RefreshTokenRouteName; + public const string SendForgottenPasswordMailRouteName = "SendForgottenPasswordMail"; + public const string SendForgottenPasswordMail = UserAPI + SendForgottenPasswordMailRouteName; + + public const string ValidateForgottenPasswordTokenRouteName = "ValidateForgottenPasswordToken"; + public const string ValidateForgottenPasswordToken = UserAPI + ValidateForgottenPasswordTokenRouteName; + //Weatherdata //public const string WeatherForecast = "api/WeatherForecastAPI"; public const string WeatherForecast = WeatherForecastAPI; From f39fc86a8471613a1ed40f7a9758f807feada7d5 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 9 Aug 2024 17:51:44 +0200 Subject: [PATCH 3/3] password change updates --- TIAM.Services/SignalRTags.cs | 3 + TIAMSharedUI/Pages/ForgottenPassword.razor | 6 +- .../CardComponents/UserCardComponent.razor | 43 +++++++++----- .../Controllers/TransferDataAPIController.cs | 27 ++++++++- .../Server/Controllers/UserAPIController.cs | 59 ++++++++++++------- TIAMWebApp/Shared/Models/APIUrls.cs | 9 +++ 6 files changed, 109 insertions(+), 38 deletions(-) diff --git a/TIAM.Services/SignalRTags.cs b/TIAM.Services/SignalRTags.cs index 32bb6e69..716f02f5 100644 --- a/TIAM.Services/SignalRTags.cs +++ b/TIAM.Services/SignalRTags.cs @@ -114,5 +114,8 @@ public class SignalRTags : AcSignalRTags public const int UserChangePassword = 139; public const int UserForgotPassword = 140; + public const int GuestUpdateTransfer = 150; + public const int DriverUpdateTransfer = 151; + public const int GetAllLogItemsByFilterText = 1000; } diff --git a/TIAMSharedUI/Pages/ForgottenPassword.razor b/TIAMSharedUI/Pages/ForgottenPassword.razor index 92dd2e7b..aa678f13 100644 --- a/TIAMSharedUI/Pages/ForgottenPassword.razor +++ b/TIAMSharedUI/Pages/ForgottenPassword.razor @@ -34,16 +34,18 @@
@_localizer["LoginTitleText"]
+
- Send +
+ Send
No account yet? Sign up here!
diff --git a/TIAMSharedUI/Pages/User/CardComponents/UserCardComponent.razor b/TIAMSharedUI/Pages/User/CardComponents/UserCardComponent.razor index 71dc731a..99f5b949 100644 --- a/TIAMSharedUI/Pages/User/CardComponents/UserCardComponent.razor +++ b/TIAMSharedUI/Pages/User/CardComponents/UserCardComponent.razor @@ -14,18 +14,25 @@ @inject AdminSignalRClient AdminSignalRClient;
-
-
- -
-
-
@($"{Context.UserDto.Id}")
-

@Context.UserDto.EmailAddress

-

@Context.UserDto.PhoneNumber

-
-
-
+ @{ + if(!IsForgotten) + { +
+
+ +
+
+
@($"{Context.UserDto.Id}")
+

@Context.UserDto.EmailAddress

+

@Context.UserDto.PhoneNumber

+
+
+ +
+ } + } +
@@ -33,10 +40,16 @@
-