Initial ...
This commit is contained in:
@@ -0,0 +1,722 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels.Constants;
|
||||
using xIdentityModels.Extensions;
|
||||
using xIdentityModels.Models;
|
||||
using xIdentityModels.Navigations;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region Action Handlers ...
|
||||
/// <summary>
|
||||
/// Request an Action
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="userSelectByParam">specified user's identifier</param>
|
||||
/// <param name="step">a member of <see>XAction</see> which represent Action Step</param>
|
||||
/// <param name="context">an instance of <see>XActionRequestContext</see> which provides required informations for specified step</param>
|
||||
/// <param name="forceCheckContext">specify checking context, default is false</param>
|
||||
/// <param name="forceCheckUserExists">specify check user exists, default is true</param>
|
||||
/// <param name="forceCheckUserDevice">specify check user and device relation, default is false</param>
|
||||
/// <param name="forceRenewToken">specifies force renew Action Token if it's expired, default is false</param>
|
||||
/// <returns>an instance of <see>XActionResponse</see></returns>
|
||||
private async Task<XActionResponse> ActionRequest(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string userSelectByParam,
|
||||
XAction step,
|
||||
XActionRequestContext context = null,
|
||||
bool forceCheckContext = false,
|
||||
bool forceCheckUserExists = true,
|
||||
bool forceCheckUserDevice = false,
|
||||
bool forceRenewToken = false
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(lang);
|
||||
ValidationProvider.NotNull(device);
|
||||
|
||||
//
|
||||
// Check Device not Banned ...
|
||||
await ValidateDeviceForActions(device);
|
||||
|
||||
//
|
||||
// Check User Exists and Device Relation ...
|
||||
if (forceCheckUserExists)
|
||||
{
|
||||
if (forceCheckUserDevice)
|
||||
{
|
||||
//
|
||||
if (context.Device != null &&
|
||||
!device.IsSameAs(context.Device))
|
||||
{
|
||||
XException.InvalidDevice.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
await ValidateUserAndDeviceRelation(userSelectByParam, device);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ValidateUserExistsAsync(userSelectByParam);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
XToken xToken = null;
|
||||
XActionResponse result = null;
|
||||
XActionRequestToken xRequest = null;
|
||||
|
||||
//
|
||||
var isExists = false;
|
||||
var forceUserSelectByParamNotEmpty = true;
|
||||
switch (step)
|
||||
{
|
||||
case XAction.Registration:
|
||||
//
|
||||
forceUserSelectByParamNotEmpty = false;
|
||||
isExists = await IsTokenExistsByDeviceAndType(device, step);
|
||||
|
||||
//
|
||||
if (isExists)
|
||||
{
|
||||
xToken = await ValidateAndRetieveTokenByDeviceAndType(device, step);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//
|
||||
isExists = await IsTokenExistsByUserAndType(userSelectByParam, step);
|
||||
|
||||
//
|
||||
if (isExists)
|
||||
{
|
||||
xToken = await ValidateAndRetieveTokenByUserAndType(userSelectByParam, step);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
if (isExists)
|
||||
{
|
||||
//
|
||||
var isValidToken = IsValidToken(xToken.Token);
|
||||
if (!isValidToken && !forceRenewToken)
|
||||
{
|
||||
switch (step)
|
||||
{
|
||||
case XAction.Registration:
|
||||
case XAction.Invite:
|
||||
forceRenewToken = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw XException.InvalidToken.ToException();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
if (!isValidToken && forceRenewToken)
|
||||
{
|
||||
await ValidateAndHandleToken(xToken.Token);
|
||||
return await ActionRequest(
|
||||
lang,
|
||||
device,
|
||||
userSelectByParam,
|
||||
step,
|
||||
context,
|
||||
forceCheckContext,
|
||||
forceCheckUserExists,
|
||||
forceCheckUserDevice,
|
||||
forceRenewToken);
|
||||
}
|
||||
|
||||
//
|
||||
xRequest = ValidateAndParseActionToken(xToken.Token);
|
||||
|
||||
//
|
||||
// Check Exists Context ...
|
||||
if (forceCheckContext)
|
||||
{
|
||||
//
|
||||
var isSameContext = xRequest.Context.IsSameAs(context);
|
||||
if (!isSameContext)
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
if (context != null)
|
||||
{
|
||||
//
|
||||
var contextUserSelectByParam = GetUserSelectByParam(
|
||||
context,
|
||||
false,
|
||||
new List<XUserSelectBy> {
|
||||
XUserSelectBy.ID,
|
||||
XUserSelectBy.Email,
|
||||
XUserSelectBy.MobileNumber
|
||||
});
|
||||
var contextLang = context.Lang;
|
||||
var contextDevice = context.Device;
|
||||
|
||||
//
|
||||
// prevent from issues on Registration Request ...
|
||||
if (forceUserSelectByParamNotEmpty)
|
||||
{
|
||||
var userSelectByType = GetUserSelectByType(userSelectByParam);
|
||||
var contextUserSelectByType = GetUserSelectByType(contextUserSelectByParam);
|
||||
if (contextUserSelectByType != userSelectByType)
|
||||
{
|
||||
//
|
||||
var excludesList = GenerateUserSelectByExcludes(new List<XUserSelectBy> { userSelectByType });
|
||||
|
||||
//
|
||||
contextUserSelectByParam = GetUserSelectByParam(context, false, excludesList);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Fix Device Not Same on Invitation and Request
|
||||
if (step == XAction.Registration)
|
||||
{
|
||||
//
|
||||
context.Device = device;
|
||||
contextDevice = context.Device;
|
||||
}
|
||||
|
||||
//
|
||||
// Validate Context Data must be Same as Request Data ...
|
||||
if ((!contextUserSelectByParam.IsNullOrEmpty() &&
|
||||
contextUserSelectByParam != userSelectByParam) ||
|
||||
(!contextLang.IsNullOrEmpty() &&
|
||||
contextLang != lang) ||
|
||||
(contextDevice != null &&
|
||||
!contextDevice.IsSameAs(device)))
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
context = new XActionRequestContext
|
||||
{
|
||||
Lang = lang,
|
||||
Device = device
|
||||
};
|
||||
|
||||
//
|
||||
// Add Content ...
|
||||
var userSelectByType = GetUserSelectByType(
|
||||
userSelectByParam,
|
||||
forceUserSelectByParamNotEmpty);
|
||||
switch (userSelectByType)
|
||||
{
|
||||
case XUserSelectBy.MobileNumber:
|
||||
context.MobileNumber = userSelectByParam;
|
||||
break;
|
||||
|
||||
case XUserSelectBy.Email:
|
||||
context.Email = userSelectByParam;
|
||||
break;
|
||||
|
||||
case XUserSelectBy.Username:
|
||||
context.UserName = userSelectByParam;
|
||||
break;
|
||||
|
||||
case XUserSelectBy.ID:
|
||||
context.UserId = userSelectByParam;
|
||||
break;
|
||||
|
||||
case XUserSelectBy.NotSpecified:
|
||||
default:
|
||||
if (forceCheckUserExists)
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Generate Registration Request ...
|
||||
xRequest = new XActionRequestToken
|
||||
{
|
||||
Action = step,
|
||||
Context = context
|
||||
};
|
||||
|
||||
//
|
||||
// Add User Id if Exists to Context ...
|
||||
var isUserExists = await IsUserExistsAsync(userSelectByParam);
|
||||
if (isUserExists)
|
||||
{
|
||||
//
|
||||
var user = await GetUserAsync(userSelectByParam);
|
||||
if (user != null)
|
||||
{
|
||||
xRequest.Context.UserId = user.Id;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
xRequest.Prepare(Configuration.IdentitySecretKey);
|
||||
|
||||
//
|
||||
xToken = await HashRequest(
|
||||
xRequest,
|
||||
forceUserSelectByParamNotEmpty);
|
||||
}
|
||||
|
||||
//
|
||||
// When XToken Exists Passed XToken ...
|
||||
result = GetActionResultResponse(xToken);
|
||||
|
||||
//
|
||||
if (result == null)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request a Mobile Verification Code
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="actionToken">a token which approved user action</param>
|
||||
/// <param name="mobileNumber">the mobile number which is going to request a verification code</param>
|
||||
/// <param name="checkMobileInUse">check mobile number is in use or not, default is true</param>
|
||||
/// <returns>an instance of <see>XActionResponse</see></returns>
|
||||
private async Task<XActionResponse> RequestMobileVerificationCode(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string actionToken,
|
||||
string mobileNumber,
|
||||
bool checkMobileInUse = true
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotEmpty(lang, actionToken, mobileNumber)
|
||||
.AddMobileNumber(mobileNumber)
|
||||
.AddNotNull(device)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
// Check Device Validation ...
|
||||
await ValidateDeviceForActions(device);
|
||||
|
||||
//
|
||||
// Check Mobile is Unique ...
|
||||
if (checkMobileInUse)
|
||||
{
|
||||
var isUserExists = await IsUserExistsAsync(mobileNumber);
|
||||
if (isUserExists)
|
||||
{
|
||||
//
|
||||
var xUser = await GetUserAsync(mobileNumber);
|
||||
|
||||
//
|
||||
if (xUser.PhoneNumberConfirmed)
|
||||
{
|
||||
XException.MobileInUsed.Throw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Get Related Token to Registration Hash and Validate it,
|
||||
// then Parse XActionRequest Instance from Token ...
|
||||
var request = await ValidateAndParseActionHash(actionToken);
|
||||
|
||||
//
|
||||
// Validate two Device Must Same ...
|
||||
ValidateRequestAndGiveDevices(device, request.Context.Device);
|
||||
|
||||
//
|
||||
// Extract UserSelectByParam from XActionRequest ...
|
||||
var userSelectByParam = GetUserSelectByParam(
|
||||
request,
|
||||
forceNotNull: false,
|
||||
excludes: new List<XUserSelectBy> {
|
||||
XUserSelectBy.ID,
|
||||
XUserSelectBy.Email,
|
||||
XUserSelectBy.MobileNumber
|
||||
});
|
||||
|
||||
//
|
||||
// if it's null, means user doesn't have Invitation Token
|
||||
// and there is no User Selector ...
|
||||
if (userSelectByParam.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
// Since Mobile is Unique so it can act as a
|
||||
// UserSelector ...
|
||||
userSelectByParam = mobileNumber;
|
||||
}
|
||||
|
||||
//
|
||||
// Define empty Verification Code
|
||||
// and Empty Verification Request ...
|
||||
var verificationCode = "";
|
||||
XVerificationRequest xVerificationRequest = null;
|
||||
|
||||
//
|
||||
// Check Device Request Verification Code before or Not ...
|
||||
var isDeviceRequested = await IsDeviceRequestedForVerificationCodeBefor(device);
|
||||
if (isDeviceRequested)
|
||||
{
|
||||
//
|
||||
// if Requested before, Retrieve XVerification instance by Device from Db
|
||||
// and Validate it ...
|
||||
xVerificationRequest = await ValidateAndRetrieveVerificationRequest(device);
|
||||
|
||||
//
|
||||
if (xVerificationRequest.VerificationCode.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
verificationCode = GenerateRandom().ToString();
|
||||
xVerificationRequest.VerificationCode = verificationCode;
|
||||
|
||||
//
|
||||
await RemoveVerificationCodeRequestByDevice(
|
||||
device,
|
||||
saveChanges: false
|
||||
);
|
||||
await AddVerificationRequest(
|
||||
xVerificationRequest,
|
||||
saveChanges: false
|
||||
);
|
||||
|
||||
//
|
||||
await DbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
//
|
||||
// if XVerificationRequest is Valid, it must Contain an Alive Verification Code
|
||||
// so retrieve it and assign it ...
|
||||
verificationCode = xVerificationRequest.VerificationCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
verificationCode = GenerateRandom().ToString();
|
||||
}
|
||||
|
||||
//
|
||||
// if it's First Verification Request of given Device
|
||||
// Generate a new Verification Code ...
|
||||
if (verificationCode.IsNullOrEmpty())
|
||||
{
|
||||
verificationCode = GenerateRandom().ToString();
|
||||
}
|
||||
|
||||
//
|
||||
// Check Context Mobile and given Mobile ...
|
||||
if (!request.Context.MobileNumber.IsNullOrEmpty() &&
|
||||
mobileNumber != request.Context.MobileNumber)
|
||||
{
|
||||
XException.InvalidMobileNumber.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Check User Added To Db or Not ...
|
||||
var isAddedUser = !request.Context.UserId.IsNullOrEmpty();
|
||||
if (isAddedUser)
|
||||
{
|
||||
//
|
||||
// Validate User Exists and Retireve User Object ...
|
||||
var user = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
containDetails: false,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false);
|
||||
|
||||
//
|
||||
// Check Mobiles Same ...
|
||||
if (user.PhoneNumber == mobileNumber &&
|
||||
user.PhoneNumberConfirmed)
|
||||
{
|
||||
XException.MobilesSame.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Update User Object's Mobile Number and
|
||||
// Confirmation Status ...
|
||||
user.PhoneNumber = mobileNumber;
|
||||
user.PhoneNumberConfirmed = false;
|
||||
|
||||
//
|
||||
// Save Changes to Db ...
|
||||
await UpdateUserAsync(user, checkCanLoginPolicies: false, checkIsBanned: false);
|
||||
}
|
||||
|
||||
//
|
||||
// Prepare Verification Request by Checking Next Tries,
|
||||
// Device Status, and etc, Update or Add XVerificationRequest to db
|
||||
// and Retrieve the added Entity ...
|
||||
xVerificationRequest = await HandleVerificationRequestPreparation(verificationCode, request);
|
||||
|
||||
//
|
||||
// Update Request Context MobileNumber
|
||||
// and it's Confirmation Status ...
|
||||
request.Context.MobileNumber = mobileNumber;
|
||||
request.Context.MobileVerified = false;
|
||||
|
||||
//
|
||||
// Remove Previous Token ...
|
||||
await RemoveTokenByHash(actionToken);
|
||||
|
||||
//
|
||||
// Prepare New Token Result Resource,
|
||||
// by Requesting an Action ...
|
||||
var result = await ActionRequest(
|
||||
lang,
|
||||
device,
|
||||
userSelectByParam,
|
||||
XAction.RequestMobileVerificationCode,
|
||||
request.Context,
|
||||
forceCheckUserExists: isAddedUser
|
||||
);
|
||||
|
||||
//
|
||||
// Prepare Message ...
|
||||
var xMessage = GetVerificationCodeMessage(lang, mobileNumber, verificationCode);
|
||||
|
||||
//
|
||||
// Send Verification Code Message to User Using SMS Provider ...
|
||||
await MessageProvider.SendSmsAsync(xMessage, throwException: false);
|
||||
|
||||
//
|
||||
// Return Result ...
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request a Email Verification Code
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="actionToken">a token which approved user action</param>
|
||||
/// <param name="emailAddress">the email address which is going to request a verification code</param>
|
||||
/// <param name="checkEmailInUse">check email address is in use or not, default is true</param>
|
||||
/// <returns>an instance of <see>XActionResponse</see></returns>
|
||||
public async Task<XActionResponse> RequestEmailVerificationCode(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string actionToken,
|
||||
string emailAddress,
|
||||
bool checkEmailInUse = true
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotEmpty(lang, actionToken, emailAddress)
|
||||
.AddEmailAddress(emailAddress)
|
||||
.AddNotNull(device)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
// Check Device Validation ...
|
||||
await ValidateDeviceForActions(device);
|
||||
|
||||
//
|
||||
// Check Email is Unique ...
|
||||
if (checkEmailInUse)
|
||||
{
|
||||
var isUserExists = await IsUserExistsAsync(emailAddress);
|
||||
if (isUserExists)
|
||||
{
|
||||
//
|
||||
var xUser = await GetUserAsync(emailAddress);
|
||||
|
||||
//
|
||||
if (xUser.EmailConfirmed)
|
||||
{
|
||||
XException.EmailInUsed.Throw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Get Related Token to Registration Hash and Validate it,
|
||||
// then Parse XActionRequest Instance from Token ...
|
||||
var request = await ValidateAndParseActionHash(actionToken);
|
||||
|
||||
//
|
||||
// Validate two Device Must Same ...
|
||||
ValidateRequestAndGiveDevices(device, request.Context.Device);
|
||||
|
||||
//
|
||||
// Extract UserSelectByParam from XActionRequest ...
|
||||
var userSelectByParam = GetUserSelectByParam(
|
||||
request,
|
||||
forceNotNull: false,
|
||||
excludes: new List<XUserSelectBy> {
|
||||
XUserSelectBy.ID,
|
||||
XUserSelectBy.Email,
|
||||
XUserSelectBy.MobileNumber
|
||||
});
|
||||
|
||||
//
|
||||
// if it's null, means user doesn't have Invitation Token
|
||||
// and there is no User Selector ...
|
||||
if (userSelectByParam.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
// Since Email is Unique so it can act as a
|
||||
// UserSelector ...
|
||||
userSelectByParam = emailAddress;
|
||||
}
|
||||
|
||||
//
|
||||
// Define empty Verification Code
|
||||
// and Empty Verification Request ...
|
||||
var verificationCode = "";
|
||||
XVerificationRequest xVerificationRequest = null;
|
||||
|
||||
//
|
||||
// Check Device Request Verification Code before or Not ...
|
||||
var isDeviceRequested = await IsDeviceRequestedForVerificationCodeBefor(device);
|
||||
if (isDeviceRequested)
|
||||
{
|
||||
//
|
||||
// if Requested before, Retrieve XVerification instance by Device from Db
|
||||
// and Validate it ...
|
||||
xVerificationRequest = await ValidateAndRetrieveVerificationRequest(device);
|
||||
|
||||
//
|
||||
if (xVerificationRequest.VerificationCode.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
verificationCode = GenerateRandom().ToString();
|
||||
xVerificationRequest.VerificationCode = verificationCode;
|
||||
|
||||
//
|
||||
await RemoveVerificationCodeRequestByDevice(
|
||||
device,
|
||||
saveChanges: false
|
||||
);
|
||||
await AddVerificationRequest(
|
||||
xVerificationRequest,
|
||||
saveChanges: true
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// if XVerificationRequest is Valid, it must Contain an Alive Verification Code
|
||||
// so retrieve it and assign it ...
|
||||
verificationCode = xVerificationRequest.VerificationCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
verificationCode = GenerateRandom().ToString();
|
||||
}
|
||||
|
||||
//
|
||||
// Check Context Email and given Email ...
|
||||
if (!request.Context.Email.IsNullOrEmpty() &&
|
||||
emailAddress != request.Context.Email)
|
||||
{
|
||||
XException.InvalidEmailAddress.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Check User Added To Db or Not ...
|
||||
var isAddedUser = !request.Context.UserId.IsNullOrEmpty();
|
||||
if (isAddedUser)
|
||||
{
|
||||
//
|
||||
// Validate User Exists and Retireve User Object ...
|
||||
var user = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
containDetails: false,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false);
|
||||
|
||||
//
|
||||
// Check Email Same ...
|
||||
if (user.Email == emailAddress &&
|
||||
user.EmailConfirmed)
|
||||
{
|
||||
XException.MobilesSame.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Update User Object's Email and
|
||||
// Confirmation Status ...
|
||||
user.Email = emailAddress;
|
||||
user.EmailConfirmed = false;
|
||||
|
||||
//
|
||||
// Save Changes to Db ...
|
||||
await UpdateUserAsync(
|
||||
user,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Prepare Verification Request by Checking Next Tries,
|
||||
// Device Status, and etc, Update or Add XVerificationRequest to db
|
||||
// and Retrieve the added Entity ...
|
||||
xVerificationRequest = await HandleVerificationRequestPreparation(verificationCode, request);
|
||||
|
||||
//
|
||||
// Update Request Context Email
|
||||
// and it's Confirmation Status ...
|
||||
request.Context.Email = emailAddress;
|
||||
request.Context.EmailVerified = false;
|
||||
|
||||
//
|
||||
// Prepare New Token Result Resource,
|
||||
// by Requesting an Action ...
|
||||
var result = await ActionRequest(
|
||||
lang,
|
||||
device,
|
||||
userSelectByParam,
|
||||
XAction.RequestEmailVerificationCode,
|
||||
request.Context,
|
||||
forceCheckUserExists: isAddedUser
|
||||
);
|
||||
|
||||
//
|
||||
// Remove Hash ...
|
||||
await RemoveTokenByHash(actionToken);
|
||||
|
||||
//
|
||||
// Prepare Message ...
|
||||
var xMessage = GetVerificationCodeMessage(lang, emailAddress, verificationCode);
|
||||
|
||||
//
|
||||
// Send Verification Code Message to User Using Mail Provider ...
|
||||
await MessageProvider.SendMailAsync(xMessage, throwException: false);
|
||||
|
||||
//
|
||||
// Return Result ...
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user