700 lines
23 KiB
C#
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
|
|
}
|
|
} |