WIP renew password, email template handling and usage

This commit is contained in:
Adam 2024-08-08 20:16:14 +02:00
parent a7e8831ff9
commit 1cbf88d563
18 changed files with 661 additions and 59 deletions

View File

@ -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<string, Guid> SysAccounts = new Dictionary<string, Guid>
{
{ "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<string> WelcomeEmailParameters = new List<string>()
{
"UserName",
"ActivationCode"
};
public static List<string> ForgotPasswordEmailParameters = new List<string>()
{
//string userName, string settingBaseUrl, string userId, string token
"UserName",
"SettingBaseUrl",
"UserId",
"Token"
};
public static List<string> NewTransferEmailParameters = new List<string>()
{
//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
}

View File

@ -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<string, string> 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<string, string>
{
{ 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<string, string>
{
{ 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<string, string>
{
{ 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);
}
}
}

View File

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

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<body>
<p>Dear {{UserName}},</p>
<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>
<p>{{FullName}}</p>
<p>{{PassengerCount}}</p>
<p>{{LuggageCount}}</p>
<p>Please confirm the transfer by clicking on the following link:</p>
<p><a href="{{SettingBaseUrl}}/mytransfers/{{TransferId}}">Confirm Transfer</a></p>
<p>If you did not request this transfer, please disregard this email.</p>
<p>Thank you,<br />Tour I Am team</p>
</body>
</html>

View File

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

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<h1>Hello, {{UserName}}!</h1>
<p>Thank you for joining us.</p>
<p>Your activation code is: {{ActivationCode}}</p>
</body>
</html>

View File

@ -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<string, string>
{
{ "UserName", userName },
{ "ActivationCode", activationCode }
};
return EmailTemplateHelper.ReplacePlaceholders(template, placeholders);
}
}
}

View File

@ -6,6 +6,25 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Remove="EmbeddedResources\EmailTemplates\ForgotPasswordEmailTemplate.html" />
<None Remove="EmbeddedResources\EmailTemplates\NewTransferEmailTemplate.html" />
<None Remove="EmbeddedResources\EmailTemplates\TransferModifiedEmailTemplate.html" />
<None Remove="EmbeddedResources\EmailTemplates\WelcomeEmailTemplate.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="EmbeddedResources\EmailTemplates\ForgotPasswordEmailTemplate.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="EmbeddedResources\EmailTemplates\NewTransferEmailTemplate.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="EmbeddedResources\EmailTemplates\TransferModifiedEmailTemplate.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.7" />
<PackageReference Include="SendGrid" Version="9.29.3" />
@ -64,4 +83,10 @@
<Folder Include="Interfaces\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="EmbeddedResources\EmailTemplates\WelcomeEmailTemplate.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@ -324,6 +324,39 @@ namespace TIAMMobileApp.Services
return result;
}
public async Task<bool> 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<bool>();
_logger.Detail($"SendForgottenPasswordMail(): {success.ToString()}");
return success;
}
public async Task<string> 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<string>();
if (success == "Success")
{
_logger.Detail($"SendForgottenPasswordMail(): {success}");
}
return success;
}
//public Task<Dictionary<int, string>> GetUserRolesAsync(UserModel userModel)
//{
// //TODO Finish this

View File

@ -1,4 +1,6 @@
@using TIAMWebApp.Shared.Application.Models.PageModels;
@using AyCode.Core.Consts
@using TIAM.Core.Consts
@using TIAMWebApp.Shared.Application.Models.PageModels;
<EditForm Model="@LoginModel" OnValidSubmit="GoToNextStep">
@* <DataAnnotationsValidator /> *@
@ -44,7 +46,7 @@
IEnumerable<char> PredefinedPlaceholders { get; set; } = new List<char>() { '_', '#' };
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;

View File

@ -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
<PageTitle>Forgot password</PageTitle>
<div class="text-center m-5">
<h1>Renew password</h1>
<h2 style="font-size:small">Good to see you again!</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 glass inputwizardwrapper my-5">
<div class="wrapper">
<div class="my-logo">
<img src="_content/TIAMSharedUI/images/png-logo-0.png" alt="">
</div>
<div class="text-center mt-4 name">
@_localizer["LoginTitleText"]
</div>
<DxMaskedInput @bind-Value="@emailAddress"
Id="Email"
CssClass="cw-320"
Mask="@EmailMask"
MaskMode="MaskMode.RegEx">
<DxRegExMaskProperties MaskAutoCompleteMode="@((MaskAutoCompleteMode)AutoCompleteMode)"
Placeholder="Placeholder"
PlaceholdersVisible="PlaceholderVisible" />
</DxMaskedInput>
<DxButton RenderStyle="ButtonRenderStyle.Primary" Click="() => SendMail(emailAddress)">Send</DxButton>
<div class="text-center fs-6">
No account yet? <a href="register">Sign up here!</a>
</div>
<div class="text-center fs-6">
Figured it out? <a href="login">Back to login!</a>
</div>
</div>
</div>
</Animation>
</div>
<div class="col-12 col-sm-6 px-5">
<Animation Effect="@Effect.FadeIn" Speed="@Speed.Fast" Delay="@TimeSpan.FromMilliseconds(250)">
<p>
@msg;
</p>
</Animation>
</div>
</div>
</div>
@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;
}
}

View File

@ -61,7 +61,7 @@
No account yet? <a href="register">Sign up here!</a>
</div>
<div class="text-center fs-6">
Forgot your password? <a href="renewpassword">Click here!</a>
Forgot your password? <a href="forgotpassword">Click here!</a>
</div>
</div>
</div>

View File

@ -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
<PageTitle>Forgot password</PageTitle>
<PageTitle>Renew password</PageTitle>
<div class="text-center m-5">
<h1>Renew password</h1>
@ -20,22 +25,47 @@
<div class="col-12 col-sm-6 px-5">
<Animation Effect="@Effect.FadeIn" Speed="@Speed.Slow" Delay="@TimeSpan.FromMilliseconds(250)">
<div class="card glass inputwizardwrapper my-5">
@{
if (!isFormHidden)
{
<div class="wrapper">
<div class="my-logo">
<img src="_content/TIAMSharedUI/images/png-logo-0.png" alt="">
</div>
<div class="text-center mt-4 name">
@_localizer["LoginTitleText"]
</div>
<UserCardComponent DataChanged="SendForm" Context="user" IsForgotten="true" />
<div class="text-center fs-6">
No account yet? <a href="register">Sign up here!</a>
</div>
<div class="text-center fs-6">
Figured it out? <a href="login">Back to login!</a>
</div>
</div>
}
else
{
<div class="wrapper">
<div class="my-logo">
<img src="_content/TIAMSharedUI/images/png-logo-0.png" alt="">
</div>
<div class="text-center mt-4 name">
@_localizer["LoginTitleText"]
</div>
<p>@resultMsg</p>
<div class="text-center fs-6">
No account yet? <a href="register">Sign up here!</a>
</div>
<div class="text-center fs-6">
Figured it out? <a href="login">Back to login!</a>
</div>
</div>
}
}
<div class="wrapper">
<div class="my-logo">
<img src="_content/TIAMSharedUI/images/png-logo-0.png" alt="">
</div>
<div class="text-center mt-4 name">
@_localizer["LoginTitleText"]
</div>
<UserCardComponent Context="user" IsForgotten="true" />
<div class="text-center fs-6">
No account yet? <a href="register">Sign up here!</a>
</div>
<div class="text-center fs-6">
Figured it out? <a href="login">Back to login!</a>
</div>
</div>
</div>
</Animation>
</div>
@ -52,13 +82,54 @@
</div>
@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. ";
}
}
}

View File

@ -62,7 +62,7 @@
@code {
[Parameter] public UserModelDtoDetail Context { get; set; }
[Parameter] public EventCallback<string> DataChanged { get; set; }
[Parameter] public EventCallback<bool> 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()
{

View File

@ -331,6 +331,34 @@ namespace TIAMWebApp.Client.Services
return result;
}
public async Task<bool> 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<bool>();
_logger.Detail($"SendForgottenPasswordMail(): {success.ToString()}");
return success;
}
public async Task<string> 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<Dictionary<int, string>> GetUserRolesAsync(UserModel userModel)
{
//TODO: finish this

View File

@ -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<IAcLogWriterBase> logWriters) : ControllerBase, IUserApiControllerCommon
public class UserAPIController(IConfiguration configuration, AdminDal adminDal, UserDal userDal, IMessageSenderService messageSenderService, IEnumerable<IAcLogWriterBase> logWriters) : ControllerBase, IUserApiControllerCommon
{
private readonly TIAM.Core.Loggers.Logger<UserAPIController> _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<IAcConsoleLogWriter>()?.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<UserModelDtoDetail?> 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<UserModelDto>? GetUserByEmail(string email)
{
_logger.Info($"GetUserByEmail called with email: {email}");
_logger.Info($"GetUserByEmail called with email: {email}");
var result = await userDal.GetUserModelDtoByEmailAsync<UserModelDto>(email, false);
if (result == null)
{
@ -441,8 +447,112 @@ namespace TIAMWebApp.Server.Controllers
public async Task<UserModelDtoDetail?> GetUserDetailById([FromBody] Guid id)
{
_logger.Info($"GetUserDetailById called with id: {id}");
var result = await userDal.GetUserModelDtoByIdAsync<UserModelDtoDetail>(id, true);
var result = await userDal.GetUserModelDtoByIdAsync<UserModelDtoDetail>(id, false);
return result;
}
[AllowAnonymous]
[HttpPost]
[Route(APIUrls.SendForgottenPasswordMailRouteName)]
public async Task<bool> 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<EmailMessage>();
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 $@"
// <html>
// <body>
// <p>Dear {user.Profile.FirstName},</p>
// <p>Please follow the link below to renew your password:</p>
// <p>
// <p><a href=""{Setting.BaseUrl}/renewpassword/{user.Id}/{email}"">Confirm Transfer</a></p>
// <p>If you did not request this, please disregard this email.</p>
// <p>Thank you,<br/>Tour I Am team</p>
// </body>
// </html>";
//}
//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<string> 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";
}
}
}
}

View File

@ -26,5 +26,9 @@ namespace TIAMWebApp.Shared.Application.Interfaces
Task<bool> RefreshToken();
public Task<bool> Logout(string refreshToken);
public Task<bool> SendForgottenPasswordMail(string emailAddress);
public Task<string> ValidateForgotPasswordToken(Guid userId, string token);
}
}

View File

@ -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;