Files
xSaherElmIds/Providers/XIdentityManager/XIdentityManager+Registration.cs
2026-03-22 14:08:25 +03:30

700 lines
23 KiB
C#

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using xCommons.Extensions;
using xExceptions.Constants;
using xIdentityModels;
using xIdentityModels.Constants;
using xIdentityModels.Models;
using xIdentityModels.Navigations;
namespace xIds.Providers
{
public partial class XIdentityManager
{
//
#region Registration Actions ...
/// <summary>
/// Invite a User to Register on Dashboard
/// </summary>
/// <param name="lang">specify destination language</param>
/// <param name="device">an instance of <see>XDevice</see></param>
/// <param name="email">which email address is going to invite</param>
/// <param name="returnUrl">return url for invitation user to redirect</param>
/// <returns>an instance of <see>XActionResponse</see></returns>
public async Task<XActionResponse> InviteUser(
string lang,
XDevice device,
string email,
string returnUrl
)
{
//
// Validate Args ...
await ValidationProvider
.GroupValidationBuilder()
.AddNotEmpty(
lang,
email,
returnUrl
)
.AddNotNull(device)
.AddEmailAddress(email)
.ValidateGroupAsync();
//
// Check Email is Unique ...
await ValidateUserNotExists(email);
//
// Get Request Result ...
var result = await ActionRequest(
lang,
device,
email,
XAction.Invite,
forceCheckContext: false,
forceCheckUserExists: false);
//
// Prepare Propper Message ...
var xMessage = GetUserInviteMessage(lang, email, result.Token, returnUrl);
//
// Send Message ...
try
{
await MessageProvider.SendMailAsync(xMessage);
}
catch { }
//
// Send Result ...
return result;
}
/// <summary>
/// Recieve some Basic Informations and Start Registration Proccess
/// if they Valid
///
/// Registration Proccess Starts with Invoking this Action
/// </summary>
/// <param name="lang">specify destination language</param>
/// <param name="device">an instance of <see>XDevice</see></param>
/// <param name="invitationHash">optional, if user invited, this is the invitation token</param>
/// <param name="firstName">user's FirstName</param>
/// <param name="lastName">user's LastName</param>
/// <param name="dateOfBirth">user's dob date</param>
/// <param name="mobileNumber">user's Mobile Number</param>
/// <param name="emailAddress">user's Email address</param>
/// <returns>an instance of <see>XActionResponse</see></returns>
public async Task<XActionResponse> RequestRegistration(
string lang,
XDevice device,
string invitationHash,
string firstName,
string lastName,
DateTime dateOfBirth,
string mobileNumber = null,
string emailAddress = null
)
{
//
// Validate Args ...
await ValidationProvider
.GroupValidationBuilder()
.AddNotEmpty(
lang,
firstName,
lastName
)
.AddNotNull(
device,
dateOfBirth
)
.ValidateGroupAsync();
//
// Validate Mobile Number if Exists ...
if (!mobileNumber.IsNullOrEmpty())
{
//
ValidationProvider.MobileNumber(mobileNumber);
//
// Check Mobile is Uniqsue ...
await ValidateUserNotExists(mobileNumber);
}
//
// Validate Email Address if Exists ...
if (!emailAddress.IsNullOrEmpty())
{
//
ValidationProvider.EmailAddress(emailAddress);
//
// Check Email is Unique ...
await ValidateUserNotExists(emailAddress);
}
//
// Get Related Token and Validate it and
// Check Related Configurations ...
await ValidateInvitationHash(invitationHash);
//
// Check Device Validation ...
await ValidateDeviceForActions(device);
//
// Validate DateOfBirth ...
ValidateDateOfBirth(dateOfBirth);
//
// Define Empty Objects for Using ...
var userSelectByParam = "";
var context = new XActionRequestContext();
//
context.Lang = lang;
context.Device = device;
context.LastName = lastName;
context.FirstName = firstName;
context.DateOfBirth = dateOfBirth;
context.MobileNumber = mobileNumber ?? "";
context.Email = !emailAddress.IsNullOrEmpty() ? emailAddress.ToNormalString() : "";
//
userSelectByParam = GetUserSelectByParam(context);
//
// Token Data Parsing ...
if (!invitationHash.IsNullOrEmpty())
{
//
// Get Related Token, Validate it and Parse Contains
// XAction Request and Validate the Request itself and
// Return it ...
var inviteRequest = await ValidateAndParseActionHash(invitationHash);
//
// Extract User Select By Param and Type ...
userSelectByParam = GetUserSelectByParam(inviteRequest);
var userSelectBy = GetUserSelectByType(userSelectByParam);
//
// Check Invitation Only done with Email Address ...
if (userSelectBy != XUserSelectBy.Email)
{
XException.InvalidData.Throw();
}
//
// Check Invited Email and Given Email to be Same ...
if (emailAddress.IsNullOrEmpty() ||
(!emailAddress.IsNullOrEmpty() &&
!emailAddress.IsValidEmail()))
{
XException.InvalidEmailAddress.Throw();
}
var isSameEmail = inviteRequest.Context.Email.ToNormalString() == emailAddress.ToNormalString();
if (!isSameEmail)
{
XException.EmailsSame.Throw();
}
//
// Update Context Email for Request Action ...
context.Email = userSelectByParam.ToNormalString();
context.EmailVerified = true;
}
//
var result = await ActionRequest(
lang,
device,
userSelectByParam,
XAction.Registration,
context,
forceCheckUserExists: false
);
//
// Remove Invitation Token ...
if (!invitationHash.IsNullOrEmpty())
{
await RemoveTokenByHash(invitationHash);
}
//
// Return Result ...
return result;
}
/// <summary>
/// Add User Account Info
/// </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="userName">user name</param>
/// <param name="password">assigne password</param>
/// <returns>an instance of <see>XActionResponse</see></returns>
public async Task<XActionResponse> AddAcountInfo(
string lang,
XDevice device,
string actionToken,
string userName,
string password
)
{
//
// Validate Args ...
await ValidationProvider
.GroupValidationBuilder()
.AddNotEmpty(
lang,
actionToken,
userName,
password)
.AddNotNull(device)
.ValidateGroupAsync();
//
// Check Device Validation ...
await ValidateDeviceForActions(device);
//
// Validate a UserSelector is Available or not ...
await ValidateCanRegister(userName);
//
// Check UserName is Unique ...
await ValidateUserNotExists(userName);
//
// Get Related Token to Registration Hash and Validate it,
// then Parse XActionRequest Instance from Token ...
var request = await ValidateAndParseActionHash(actionToken);
//
// Validate Requeired Data for Register User must be in Action Context ...
await ValidationProvider
.GroupValidationBuilder()
.AddNotNull(
request.Context,
request.Context.Device,
request.Context.DateOfBirth)
.AddNotEmpty(
request.Context.Email,
request.Context.MobileNumber,
request.Context.FirstName,
request.Context.LastName)
.AddEmailAddress(request.Context.Email)
.AddMobileNumber(request.Context.MobileNumber)
.ValidateGroupAsync();
//
// Validate two Device Must Same ...
ValidateRequestAndGivenDevices(device, request.Context.Device);
//
// Extract UserSelectByParam from XActionRequest ...
var userSelectByParam = GetUserSelectByParam(request);
//
// Validate Request Pointer User doesn't Exists ...
await ValidateUserNotExists(userSelectByParam);
//
// Create an Empty Instance of XUser ...
var xUser = new XUser();
//
// Start Filling User Fields ...
xUser.UserName = userName;
xUser.Email = request.Context.Email;
xUser.PhoneNumber = request.Context.MobileNumber;
//
xUser.FirstName = request.Context.FirstName;
xUser.LastName = request.Context.LastName;
xUser.DateOfBirth = request.Context.DateOfBirth;
//
xUser.EmailConfirmed = request.Context.EmailVerified;
xUser.PhoneNumberConfirmed = request.Context.MobileVerified;
//
xUser.CreationDate = DateTime.UtcNow;
xUser.LastLogin = null;
//
#region Handling New User IsEnable State ...
//
// By Default New Users will Enables ...
xUser.IsEnable = true;
xUser.IsBanned = false;
//
// Check Auto Enable Users ...
if (Configuration.RequireRegistrationConfirm)
{
xUser.IsEnable = false;
}
//
// Check Auto Confirm Email Users ...
if (Configuration.AutoConfirmNewUsersEmail)
{
xUser.EmailConfirmed = true;
}
#endregion
//
// Check Auto Confirm Phone Number Users ...
if (Configuration.AutoConfirmNewUsersPhoneNumber)
{
xUser.PhoneNumberConfirmed = true;
}
//
// Validating given Password ...
await ValidatePasswordPolicies(xUser, password);
//
// Now add new User to Database ...
var createUserResult = await CreateUserAsync(xUser, password);
if (!createUserResult.Succeeded)
{
XException.ActionFailed.Throw();
}
//
// Update Request UserId Value ...
request.Context.UserId = xUser.Id;
request.Context.UserName = xUser.UserName;
//
#region Handling New User Role ...
//
// Now Try to Assign Default User role ...
var isContainsDefaultUserRole = !Configuration.NewUsersRole.IsNullOrEmpty();
if (isContainsDefaultUserRole)
{
//
var newUserRoleName = Configuration.NewUsersRole;
var isNewUserRoleExists = await IsRoleExistsAsync(newUserRoleName);
//
// Make Sure New User role Exists ...
if (!isNewUserRoleExists)
{
//
// Create Default Roles ...
await CreateIdentityRoles();
}
//
// Assign User to Role ...
var assignNewUserToRoleResult = await AddUserToRoleAsync(xUser, newUserRoleName);
if (!assignNewUserToRoleResult.Succeeded)
{
//
// Delete User if Role Assignment Faild ...
await UserManager.DeleteAsync(xUser);
//
// Thrown ActionFailed Error ...
XException.ActionFailed.Throw();
}
}
#endregion
//
#region Handle Profile Image ...
// Save and Attach Profile Image to User if it's Added Before ...
if (!request.Context.UserId.IsNullOrEmpty() &&
!request.Context.Thubmnail.IsNull())
{
//
xUser = await ValidateUserExistsAndRetrieve(
userSelectByParam,
containDetails: true,
checkCanLoginPolicies: false,
checkIsBanned: false,
ignoreDisabledUser: true,
exception: XException.NotFound.ToException()
);
//
// Handle Saving File and Attach it to User ...
var saveResult = await StorageProvider
.HandleProfileImageSave(request.Context.Thubmnail);
//
var xProfileImage = new XProfileImage
{
UserId = request.Context.UserId,
Name = saveResult.FileName,
Path = saveResult.FilePath,
Thumb = saveResult.Thmbnail,
ThumbPath = saveResult.ThmbnailPath
};
//
xUser.Avatars.Add(xProfileImage);
var updateResult = await UpdateUserAsync(
xUser,
checkCanLoginPolicies: false,
checkIsBanned: false
);
//
if (updateResult.Succeeded)
{
//
xUser.Avatar = xProfileImage.ThumbPath;
await UpdateUserAsync(
xUser,
checkCanLoginPolicies: false,
checkIsBanned: false
);
}
}
#endregion
//
// Handle Attaching User device ...
var xUserDevice = await AddUserRelatedDevice(
userSelectByParam,
device,
checkCanLoginPolicies: false);
//
// Prepare New Token Result Resource,
// by Requesting an Action ...
var result = await ActionRequest(
lang,
device,
userSelectByParam,
XAction.Finish,
request.Context,
forceCheckUserExists: false
);
//
// Remove Previous Token ...
await RemoveTokenByHash(actionToken);
//
// Return Result ...
return result;
}
/// <summary>
/// Attach Profile Image
/// </summary>
/// <param name="actionToken">a token which approved user action</param>
/// <param name="file">an instance of <see>IFormFile</see> for user's Avatar</param>
/// <returns>an instance of <see>XActionResponse</see></returns>
public async Task<XActionResponse> AttachProfileImage(
string actionToken,
IFormFile file
)
{
//
// Validate Args ...
await ValidationProvider
.GroupValidationBuilder()
.AddNotEmpty(actionToken)
.AddNotNull(file)
.ValidateGroupAsync();
//
// Get Related Token to Registration Hash and Validate it,
// then Parse XActionRequest Instance from Token ...
var request = await ValidateAndParseActionHash(actionToken);
//
// Extract UserSelectByParam from XActionRequest ...
var userSelectByParam = GetUserSelectByParam(request);
if (userSelectByParam.IsNullOrEmpty())
{
XException.InvalidData.Throw();
}
//
// Validate Given FormFile as Profile Image ...
StorageProvider.ValidateProfileImage(file);
//
request.Context.Thubmnail = file;
//
// Save and Attach Profile Image to User if it's Added Before ...
if (!request.Context.UserId.IsNullOrEmpty())
{
//
var xUser = await ValidateUserExistsAndRetrieve(
userSelectByParam,
containDetails: true,
checkCanLoginPolicies: false,
checkIsBanned: false,
ignoreDisabledUser: true,
exception: XException.NotFound.ToException()
);
//
// Handle Saving File and Attach it to User ...
var saveResult = await StorageProvider.HandleProfileImageSave(file);
//
var xProfileImage = new XProfileImage
{
UserId = request.Context.UserId,
Name = saveResult.FileName,
Path = saveResult.FilePath,
Thumb = saveResult.Thmbnail,
ThumbPath = saveResult.ThmbnailPath
};
//
xUser.Avatars.Add(xProfileImage);
var updateResult = await UpdateUserAsync(
xUser,
checkCanLoginPolicies: false,
checkIsBanned: false
);
//
if (updateResult.Succeeded)
{
//
xUser.Avatar = xProfileImage.ThumbPath;
await UpdateUserAsync(
xUser,
checkCanLoginPolicies: false,
checkIsBanned: false
);
}
}
//
// Remove Invitation Token ...
if (!actionToken.IsNullOrEmpty())
{
await RemoveTokenByHash(actionToken);
}
//
var result = await ActionRequest(
request.Context.Lang,
request.Context.Device,
userSelectByParam,
XAction.ProfileAction,
request.Context,
forceCheckUserExists: false
);
//
// Return Result ...
return result;
}
/// <summary>
/// Finishing Registration
/// </summary>
/// <param name="lang">specify destination language</param>
/// <param name="device">an instance of <see>XDevice</see></param>
/// <param name="userSelectByParam">user identifier</param>
/// <param name="password">assigne password</param>
/// <param name="returnUrl">return url for invitation user to redirect</param>
/// <returns></returns>
public async Task FinishRegistration(
string lang,
XDevice device,
string userSelectByParam,
string password,
string returnUrl
)
{
//
// Validate Args ...
await ValidationProvider
.GroupValidationBuilder()
.AddNotEmpty(lang, userSelectByParam, password, returnUrl)
.AddNotNull(device)
.AddUrl(returnUrl)
.ValidateGroupAsync();
//
// Validate User Exists And Retrieve it ...
var xUser = await ValidateUserExistsAndRetrieve(
userSelectByParam,
containDetails: false,
checkCanLoginPolicies: false,
checkIsBanned: false,
ignoreDisabledUser: true,
forceAdmin: false
);
//
#region Handling New User Email Notification Senario ...
//
// Here we Check if User is Enable and Approved Email
// send RegisteredMsg and if User is not Enable and
// Verify Registration value in Configuration is True
// send Verify Registration mail to user and handle it ...
if (Configuration.RequireRegistrationConfirm)
{
//
if (xUser.IsEnable)
{
//
// Send Registration Finished Message ...
// since in this step we need to prevent errors from
// going forward. add this try catch here ...
try
{
//
var xMessage = GetRegistrationFinishedMessage(lang, xUser.Email, returnUrl);
//
await MessageProvider.SendMailAsync(xMessage);
}
catch { }
}
else
{
//
// Send Registration Confirm Message ...
// since in this step we need to prevent errors from
// going forward. add this try catch here ...
try
{
//
var request = await ActionRequest(
lang,
device,
userSelectByParam,
XAction.Finish,
forceCheckContext: false,
forceCheckUserExists: true);
//
var xMessage = GetRegistrationConfirmMessage(lang, xUser.Email, request.Token, returnUrl);
//
await MessageProvider.SendMailAsync(xMessage);
}
catch { }
}
}
// //
// await RemoveTokenByDevice (device);
#endregion
}
#endregion
}
}