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 ... /// /// Invite a User to Register on Dashboard /// /// specify destination language /// an instance of XDevice /// which email address is going to invite /// return url for invitation user to redirect /// an instance of XActionResponse public async Task 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; } /// /// Recieve some Basic Informations and Start Registration Proccess /// if they Valid /// /// Registration Proccess Starts with Invoking this Action /// /// specify destination language /// an instance of XDevice /// optional, if user invited, this is the invitation token /// user's FirstName /// user's LastName /// user's dob date /// user's Mobile Number /// user's Email address /// an instance of XActionResponse public async Task 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; } /// /// Add User Account Info /// /// specify destination language /// an instance of XDevice /// a token which approved user action /// user name /// assigne password /// an instance of XActionResponse public async Task 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; } /// /// Attach Profile Image /// /// a token which approved user action /// an instance of IFormFile for user's Avatar /// an instance of XActionResponse public async Task 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; } /// /// Finishing Registration /// /// specify destination language /// an instance of XDevice /// user identifier /// assigne password /// return url for invitation user to redirect /// 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 } }