using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using xCommons.Extensions; using xExceptions.Constants; using xIdentityModels.Constants; using xIdentityModels.Dtos; using xIdentityModels.Models; using xIdentityModels.Navigations; using xModels.Dtos; using xIds.Extensions; using xIdentityModels.Extensions; using xIdentityHelper; using xIdentityHelper.Extensions; using xDataService.Extensions; namespace xIds.Providers { public partial class XIdentityManager { // #region Retrieve Actions ... /// /// Retrieve User Profile /// /// a user identifier /// requested user's identifier /// specify check requested user's identifier not empty /// and throw exception if it is, default true /// check a user can log in in system or not, default is true /// check user is banned or not, default is true /// an instance of XUserProfileDto public async Task GetUserProfileAsync( string userSelectByParam, string requestedUserSelectByParam, bool forceCheckRequestedUser = true, bool checkCanLoginPolicies = true, bool checkIsBanned = true ) { // // Data Validation ... if (forceCheckRequestedUser) { ValidationProvider.NotEmpty( userSelectByParam, requestedUserSelectByParam); } else { ValidationProvider.NotEmpty(userSelectByParam); } // var xUser = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: true, checkCanLoginPolicies: false, checkIsBanned: false, ignoreDisabledUser: true, forceAdmin: false ); // var isAdmin = false; var isSameUser = false; if (forceCheckRequestedUser && !requestedUserSelectByParam.IsNullOrEmpty()) { // var xRequestedUser = await ValidateUserExistsAndRetrieve( requestedUserSelectByParam, containDetails: true, checkCanLoginPolicies: false, checkIsBanned: false, ignoreDisabledUser: true, forceAdmin: false ); // isSameUser = xUser.Id == xRequestedUser.Id; // var xRequestUserRoleNames = await GetRoleNamesAsync( userSelectByParam: requestedUserSelectByParam, checkCanLoginPolicies: false, checkIsBanned: false ); isAdmin = xRequestUserRoleNames.Contains(XUserRole.Admin.GetStringValue()); } // var roleNames = await GetRoleNamesAsync( userSelectByParam, checkIsBanned: checkIsBanned, checkCanLoginPolicies: checkCanLoginPolicies ); // var xFriendshipInfo = requestedUserSelectByParam.IsNullOrEmpty() ? null : await GetFriendshipInfo( requestedUserSelectByParam, userSelectByParam, checkIsBanned: checkIsBanned, checkCanLoginPolicies: checkCanLoginPolicies ); // var result = xUser.ToXProfileDto( isAdmin: isAdmin, roles: roleNames, isSameUser: isSameUser, friendship: xFriendshipInfo, profileConfig: Configuration.Policy.Profile ); // return result; } /// /// Retrieve a Collection of User Profiles /// /// a collection of user identifiers /// requested user's identifier /// specify check requested user's identifier not empty /// and throw exception if it is, default true /// check a user can log in in system or not, default is true /// check user is banned or not, default is true /// an collection of XUserProfileDto instances public async Task> GetUserProfilesAsync( ICollection ids, string requestedUserSelectByParam, bool forceCheckRequestedUser = true, bool checkCanLoginPolicies = true, bool checkIsBanned = true ) { // // Data Validation ... if (forceCheckRequestedUser) { ValidationProvider.NotEmpty(requestedUserSelectByParam); } ValidationProvider.NotZeroChilds(ids); // var result = new List(); foreach (var id in ids) { // var xProfile = await GetUserProfileAsync( id, requestedUserSelectByParam, checkIsBanned: checkIsBanned, checkCanLoginPolicies: checkCanLoginPolicies, forceCheckRequestedUser: forceCheckRequestedUser ); result.Add(xProfile); } // return result; } /// /// Query User Profiles /// /// requested user's identifier /// how to filter results based on XQuery structure /// an instance of XQueryResult of XUserProfileDto public async Task> QueryUsers( string requestedUserSelectByParam, XQuery query ) { // // Validation ... if (query.IsNull()) { XException.InvalidArgs.Throw(); } // // Normalize ... query = query.NormalizeQuery(DataConfiguration.ToXDataServiceConfig()); // // Since in Resourceable Entities we have to Search on Locales // we Must Implement Senario Custom ... var totalEntities = GetUsersDbSet() .ToList() .Where(u => !u.ContainsUserSelectByParam(requestedUserSelectByParam)) .Select(u => u.Id) .ToList(); // var items = await GetUserProfilesAsync( totalEntities, requestedUserSelectByParam, checkIsBanned: false, checkCanLoginPolicies: false, forceCheckRequestedUser: false ); // var totalItemsCount = items.Count(); // // Apply Filter ... if (!query.Filter.IsNullOrEmpty()) { // items = items .ApplyFilter(query.Filter); } int filteredItemsCount = items.Count(); // // Count Pages ... var totalPagesCount = query.CountPages(totalItemsCount); var filteredPagesCount = query.CountPages(filteredItemsCount); // // Apply Paging and Sorting ... if (totalItemsCount > 0 && filteredItemsCount > 0) { // // Apply Sorting ... items = items .ToList() .ApplySorting( query.SortBy, query.IsAscending ); // // Apply Paging ... items = items .ToList() .ApplyPaging( query.Page, query.PageSize ); } // // Generate Result Object ... // Query = query, var result = new XQueryResult { Items = items, Page = query.Page, PageSize = query.PageSize, TotalPages = totalPagesCount, TotalItems = totalItemsCount, TotalFilteredPages = filteredPagesCount, TotalFilteredItems = filteredItemsCount }; // return result; } /// /// Query In Roles User Profiles /// /// requested user's identifier /// an string which represent user role /// how to filter results based on XQuery structure /// if it's true the user must has exact role, otherwise top level users also listed, default is false /// an instance of XQueryResult of XUserProfileDto public async Task> QueryInRoleUsers( string requestedUserSelectByParam, string role, XQuery query, bool forceRole = false ) { // // Validation ... if (query.IsNull() || role.IsNullOrEmpty()) { XException.InvalidArgs.Throw(); } // // Check Role Exists ... var isExistsRole = await IsRoleExistsAsync(role); if (!isExistsRole) { XException.NotFound.Throw(); } // // Normalize ... query = query.NormalizeQuery(DataConfiguration.ToXDataServiceConfig()); // #region Select Users Based on Specific Roles ... var selectedUsers = new List(); var usersEnumerator = GetUsersDbSet(query.ContainsDetail).AsAsyncEnumerable(); await foreach (var user in usersEnumerator) { // if (user.ContainsUserSelectByParam(requestedUserSelectByParam)) { continue; } // // Set Default Value is True ... var isInRole = false; // // if Force Role ... if (forceRole) { isInRole = await UserManager.IsInRoleAsync(user, role); } else { // // Select User Top Role ... var userRoles = await GetRoleNamesAsync( checkIsBanned: false, userSelectByParam: user.Id, checkCanLoginPolicies: false ); isInRole = userRoles.HasRolePermissions(role); } // if (isInRole) { selectedUsers.Add(user.Id); } } #endregion // var items = await GetUserProfilesAsync( selectedUsers, requestedUserSelectByParam, checkIsBanned: false, checkCanLoginPolicies: false, forceCheckRequestedUser: false ); // var totalItemsCount = items.Count(); // // Apply Filter ... if (!query.Filter.IsNullOrEmpty()) { // items = items .ApplyFilter(query.Filter); } int filteredItemsCount = items.Count(); // // Count Pages ... var totalPagesCount = query.CountPages(totalItemsCount); var filteredPagesCount = query.CountPages(filteredItemsCount); // // Apply Paging and Sorting ... if (totalItemsCount > 0 && filteredItemsCount > 0) { // // Apply Sorting ... items = items .ToList() .ApplySorting( query.SortBy, query.IsAscending ); // // Apply Paging ... items = items .ToList() .ApplyPaging( query.Page, query.PageSize ); } // // Generate Result Object ... // Query = query, var result = new XQueryResult { Items = items, Page = query.Page, PageSize = query.PageSize, TotalPages = totalPagesCount, TotalItems = totalItemsCount, TotalFilteredPages = filteredPagesCount, TotalFilteredItems = filteredItemsCount }; // return result; } /// /// Query Specified User's Profile Images /// /// a user identifier /// how to filter results based on XQuery structure /// an instance of XQueryResult of XProfileImage public async Task> QueryAvatars( string userSelectByParam, XQuery query ) { // // Validation ... if (query.IsNull()) { XException.InvalidArgs.Throw(); } // // Normalize ... query = query.NormalizeQuery(DataConfiguration.ToXDataServiceConfig()); // var xUser = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: true, checkCanLoginPolicies: true, checkIsBanned: true ); // var items = query.ContainsDetail ? DbContext.Avatars .Include(pf => pf.User) .AsEnumerable() : DbContext.Avatars .AsEnumerable(); items = items .Where(pfi => pfi.UserId == xUser.Id); // var totalItemsCount = items.Count(); // // Apply Filter ... if (!query.Filter.IsNullOrEmpty()) { // items = items .ApplyFilter(query.Filter); } int filteredItemsCount = items.Count(); // // Count Pages ... var totalPagesCount = query.CountPages(totalItemsCount); var filteredPagesCount = query.CountPages(filteredItemsCount); // // Apply Paging and Sorting ... if (totalItemsCount > 0 && filteredItemsCount > 0) { // // Apply Sorting ... items = items .ToList() .ApplySorting( query.SortBy, query.IsAscending ); // // Apply Paging ... items = items .ToList() .ApplyPaging( query.Page, query.PageSize ); } // // Generate Result Object ... // Query = query, var result = new XQueryResult { Items = items, Page = query.Page, PageSize = query.PageSize, TotalPages = totalPagesCount, TotalItems = totalItemsCount, TotalFilteredPages = filteredPagesCount, TotalFilteredItems = filteredItemsCount }; // return result; } /// /// Check specific user Confirmed Email or not /// /// a user identifier /// a boolean value public async Task IsConfirmedEmail( string userSelectByParam ) { // // Validate Args ... ValidationProvider.NotEmpty(userSelectByParam); // var xUser = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: false, checkCanLoginPolicies: false, checkIsBanned: false, ignoreDisabledUser: true, forceAdmin: false ); // return xUser.EmailConfirmed; } /// /// Ceck specific user Confirmed Mobile or not /// /// a user identifier /// a boolean value public async Task IsConfirmedMobile( string userSelectByParam ) { // // Validate Args ... ValidationProvider.NotEmpty(userSelectByParam); // var xUser = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: false, checkCanLoginPolicies: false, checkIsBanned: false, ignoreDisabledUser: true, forceAdmin: false ); // return xUser.PhoneNumberConfirmed; } #endregion // #region Update Actions ... /// /// Update User Profile (FirstName/LastName/DateOfBirth) ... /// /// a user identifier /// requested user's identifier /// user update info, an instance of XProfileUpdateRequest /// an instance of XUserProfileDto public async Task ProfileUpdateAsync( string userSelectByParam, string requestedUserSelectByParam, XProfileUpdateRequest model ) { // // Data Validation ... ValidationProvider.NotEmpty( userSelectByParam, requestedUserSelectByParam); ValidationProvider.NotNull(model); // var xUser = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: true, checkCanLoginPolicies: false, checkIsBanned: false, ignoreDisabledUser: true, forceAdmin: false ); // var xRequestedUser = await ValidateUserExistsAndRetrieve( requestedUserSelectByParam, containDetails: true, checkCanLoginPolicies: false, checkIsBanned: false, ignoreDisabledUser: true, forceAdmin: false ); // await ValidateUserForDangerousAction(xUser, xRequestedUser); // // FirstName ... if (!model.FirstName.IsNullOrEmpty()) { xUser.FirstName = model.FirstName; } // // Last Name ... if (!model.LastName.IsNullOrEmpty()) { xUser.LastName = model.LastName; } // // Date of Birth ... if (model.DateOfBirth.HasValue) { xUser.DateOfBirth = model.DateOfBirth.Value; } // // Bio ... xUser.Bio = model.Bio; // // Cover Image ... xUser.CoverImage = model.CoverImage; // // Open To Search ... xUser.OpenToSearch = model.OpenToSearch; // var updateResult = await UpdateUserAsync(xUser); if (!updateResult.Succeeded) { XException.ActionFailed.Throw(); } // var result = await GetUserProfileAsync(userSelectByParam, requestedUserSelectByParam); return result; } /// /// Update User Profile /// /// a user identifier /// requested user's identifier /// user update info, an instance of XProfileUpdateRequest /// an instance of XUserProfileDto public async Task FullProfileUpdateAsync( string userSelectByParam, string requestedUserSelectByParam, XProfileUpdateRequest model ) { // // Data Validation ... ValidationProvider.NotEmpty( userSelectByParam, requestedUserSelectByParam); ValidationProvider.NotNull(model); // var xUser = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: true, checkCanLoginPolicies: false, checkIsBanned: false, ignoreDisabledUser: true, forceAdmin: false ); // var xRequestedUser = await ValidateUserExistsAndRetrieve( requestedUserSelectByParam, containDetails: true, checkCanLoginPolicies: false, checkIsBanned: false, ignoreDisabledUser: true, forceAdmin: false ); // await ValidateUserForDangerousAction(xUser, xRequestedUser); // #region Fill User with Models Value ... // // FirstName ... xUser.FirstName = !model.FirstName.IsNullOrEmpty() ? model.FirstName : xUser.FirstName; // // LastName ... xUser.LastName = !model.LastName.IsNullOrEmpty() ? model.LastName : xUser.LastName; // // Email ... xUser.Email = !model.Email.IsNullOrEmpty() ? model.Email : xUser.Email; // // EmailConfirmed ... if (model.EmailConfirmed.HasValue) { xUser.EmailConfirmed = model.EmailConfirmed.Value; } // // PhoneNumber ... xUser.PhoneNumber = !model.PhoneNumber.IsNullOrEmpty() ? model.PhoneNumber : xUser.PhoneNumber; // // PhoneNumberConfirmed ,,, if (model.PhoneNumberConfirmed.HasValue) { xUser.PhoneNumberConfirmed = model.PhoneNumberConfirmed.Value; } // // DateOfBirth ... if (model.DateOfBirth.HasValue) { xUser.DateOfBirth = model.DateOfBirth.Value; } // // CreationDate ... if (model.CreationDate.HasValue) { xUser.CreationDate = model.CreationDate.Value; } // // LastLogin ... if (model.LastLogin.HasValue) { xUser.LastLogin = model.LastLogin.Value; } // // Avatar ... xUser.Avatar = !model.Avatar.IsNullOrEmpty() ? model.Avatar : xUser.Avatar; // // Gender ... if (model.Gender.HasValue) { xUser.Gender = model.Gender.Value; } // // IsEnable ... if (model.IsEnable.HasValue) { xUser.IsEnable = model.IsEnable.Value; } // // IsBanned ... if (model.IsBanned.HasValue) { xUser.IsBanned = model.IsBanned.Value; } // // Bio ... xUser.Bio = model.Bio; // // Cover Image ... xUser.CoverImage = model.CoverImage; // // Open To Search ... xUser.OpenToSearch = model.OpenToSearch; #endregion // var updateResult = await UpdateUserAsync( xUser, checkCanLoginPolicies: false, checkIsBanned: false ); if (!updateResult.Succeeded) { XException.ActionFailed.Throw(); } // // Handle Roles ... // // Remove User from All Roles ... if (xUser.Roles.HasChild()) { // var roleNames = await GetRoleNamesAsync( xUser.Id, checkIsBanned: false, checkCanLoginPolicies: false ); // foreach (var role in roleNames) { // var isRoleExists = await IsRoleExistsAsync(role); if (isRoleExists) { // var isInRole = await UserManager.IsInRoleAsync(xUser, role); if (!isInRole) { // var removeRoleResult = await UserManager.RemoveFromRoleAsync(xUser, role); if (!removeRoleResult.Succeeded) { XException.ActionFailed.Throw(); } } } } } // // Check Roles and Add to Exists ... if (model.Roles.HasChild()) { // // Check Exists Roles for Add ... foreach (var role in model.Roles) { // var isRoleExists = await IsRoleExistsAsync(role); if (isRoleExists) { // var isInRole = await UserManager.IsInRoleAsync(xUser, role); if (!isInRole) { // var addToRoleResult = await UserManager.AddToRoleAsync(xUser, role); if (!addToRoleResult.Succeeded) { XException.ActionFailed.Throw(); } } } } } // var result = await GetUserProfileAsync( userSelectByParam, requestedUserSelectByParam, checkCanLoginPolicies: false, checkIsBanned: false ); return result; } #endregion // #region Request For Actions ... /// /// Request Mobile Confirm /// /// specify destination language /// an instance of XDevice /// a user identifier /// user's password /// mobile number which need to confirm /// an instance of XActionResponse public async Task RequestConfirmMobile( string lang, XDevice device, string userSelectByParam, string password, string mobileNumber = null ) { // // Validate Args ... await ValidationProvider .GroupValidationBuilder() .AddNotEmpty( lang, userSelectByParam, password) .AddNotNull(device) .ValidateGroupAsync(); // await ValidateDeviceForActions(device); // // Prepare Request Context ... var context = new XActionRequestContext { Lang = lang, Device = device, MobileNumber = mobileNumber }; // // Validate and Retrieve User ... var user = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: false, checkCanLoginPolicies: false, checkIsBanned: false); // context.UserName = user.UserName; // await ValidateUserAndPassword( userSelectByParam, password, false, XException.ActionFailed.ToException()); // ValidationProvider.MobileNumber(user.PhoneNumber); if (!mobileNumber.IsNullOrEmpty() && user.PhoneNumber == mobileNumber && user.PhoneNumberConfirmed) { XException.MobileInUsed.Throw(); } // if (mobileNumber.IsNullOrEmpty()) { mobileNumber = user.PhoneNumber; } // // Remove All Prevoius Requests ... await HandleRemoveExistsTokens(user.Id); // // Prepare New Token Result , // by Requesting an Action ... var request = await ActionRequest( lang, device, userSelectByParam, XAction.RequestMobileVerificationCode, context, forceRenewToken: true ); // Logger.LogInformation($"ActionRequest: {request.ToJSON()}"); // // Call Confirm Method of Registration ... var result = await RequestMobileVerificationCode( lang, device, request.Token, mobileNumber, checkMobileInUse: false); // return result; } /// /// Request Email Confirma /// /// specify destination language /// an instance of XDevice /// a user identifier /// user's password /// email address which need to confirm /// an instance of XActionResponse public async Task RequestConfirmEmail( string lang, XDevice device, string userSelectByParam, string password, string emailAddress = null ) { // // Validate Args ... await ValidationProvider .GroupValidationBuilder() .AddNotEmpty( lang, userSelectByParam, password) .AddNotNull(device) .ValidateGroupAsync(); // await ValidateDeviceForActions(device); // // Prepare Request Context ... var context = new XActionRequestContext { Lang = lang, Device = device, Email = emailAddress }; // // Validate and Retrieve User ... var user = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: false, checkCanLoginPolicies: false, checkIsBanned: false); // context.UserName = user.UserName; // // Remove All Prevoius Requests ... await HandleRemoveExistsTokens(user.Id); // await ValidateUserAndPassword( userSelectByParam, password, false, XException.ActionFailed.ToException()); // ValidationProvider.EmailAddress(user.Email); if (!emailAddress.IsNullOrEmpty() && user.Email == emailAddress && user.EmailConfirmed) { XException.EmailInUsed.Throw(); } // if (emailAddress.IsNullOrEmpty()) { emailAddress = user.Email; context.Email = user.Email; } // // Prepare New Token Result , // by Requesting an Action ... var request = await ActionRequest( lang, device, userSelectByParam, XAction.RequestEmailVerificationCode, context, forceRenewToken: true ); // // Call Confirm Method of Registration ... var result = await RequestEmailVerificationCode( lang, device, request.Token, emailAddress, checkEmailInUse: false); // return result; } /// /// Request Reset Password /// /// specify destination language /// an instance of XDevice /// a user identifier /// redirection url /// an instance of XActionResponse public async Task RequestResetPassword( string lang, XDevice device, string userSelectByParam, string returnUrl ) { // // Validate Args ... await ValidationProvider .GroupValidationBuilder() .AddNotEmpty( lang, userSelectByParam, returnUrl) .AddNotNull(device) .AddUrl(returnUrl) .ValidateGroupAsync(); // await ValidateDeviceForActions(device); // // Validate and Retrieve User ... var user = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: false, checkCanLoginPolicies: true, checkIsBanned: true); // // Prepare Request Context ... var context = new XActionRequestContext { Lang = lang, Device = device, Email = user.Email, UserName = user.UserName }; // // Remove All Prevoius Requests ... await HandleCleanUserTokens(user); // // Prepare New Token Result , // by Requesting an Action ... var result = await ActionRequest( lang, device, user.Email, XAction.RequestResetPassword, context ); // // Prepare Message ... var xMessage = GetResetPasswordMessage( lang, user.Email, result.Token, returnUrl); // try { await MessageProvider.SendMailAsync(xMessage); } catch { } // return result; } /// /// Request Registration Confrirm /// /// specify destination language /// an instance of XDevice /// a user identifier /// user's password /// redirection url /// public async Task RequestConfirmRegistration( 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 and Retrieve it ... var user = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: false, checkCanLoginPolicies: false, checkIsBanned: true, ignoreDisabledUser: true); // // Prepare Request Context ... var context = new XActionRequestContext { Lang = lang, Device = device, Email = user.Email }; // await ValidateUserAndPassword( userSelectByParam, password, false, XException.ActionFailed.ToException()); // // Remove All Prevoius Requests ... await HandleRemoveExistsTokens(user.Id); // // Prepare New Token Result , // by Requesting an Action ... var result = await ActionRequest( lang, device, user.Email, XAction.Finish, context ); // // Prepare XMessage Instance ... var xMessage = GetRegistrationConfirmMessage( lang, user.Email, result.Token, returnUrl); // // Send Message ... try { await MessageProvider.SendMailAsync(xMessage); } catch { } } #endregion // #region Password Actions ... /// /// Change Password /// /// specify destination language /// an instance of XDevice /// a user identifier /// user's password /// user's new password /// redirection url /// public async Task ChangePassword( string lang, XDevice device, string userSelectByParam, string password, string newPassword, string returnUrl ) { // // Validate Args ... await ValidationProvider .GroupValidationBuilder() .AddNotEmpty( lang, userSelectByParam, password, newPassword, returnUrl) .AddNotNull(device) .ValidateGroupAsync(); // // Password Unique ... if (password == newPassword) { XException.PasswordsSame.Throw(); } // // Validate and Retrieve User ... var user = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: false, checkCanLoginPolicies: true, checkIsBanned: true); // await ValidateUserAndPassword( userSelectByParam, password); // // Check Password Policies ... await ValidatePasswordPolicies(user, newPassword); // // Clean All User Tokens ... await HandleCleanUserTokens(user); // // Try to Change User Password ... var passwordResetResult = await UserManager .ChangePasswordAsync( user, password, newPassword); // // Check Result ... if (!passwordResetResult.Succeeded) { XException.ActionFailed.Throw(); } // // Prepare Message ... var xMessage = GetPasswordChangedMessage( lang, user.Email, returnUrl, throwException: false ); // // Send Message ... try { await MessageProvider.SendMailAsync(xMessage); } catch { } } /// /// Reset User Password /// /// specify destination language /// an instance of XDevice /// a token which approved user action /// user's new password /// redirection url /// public async Task ResetPassword( string lang, XDevice device, string actionToken, string newPassword, string returnUrl ) { // // Validate Args ... await ValidationProvider .GroupValidationBuilder() .AddNotEmpty( lang, actionToken, newPassword, returnUrl) .AddNotNull(device) .ValidateGroupAsync(); // // Get Related Token to Registration Hash and Validate it, // then Parse XActionRequest Instance from Token ... var request = await ValidateAndParseActionHash(actionToken); // // Get User Identifier ... var userSelectByParam = GetUserSelectByParam(request); // // Validate and Retrieve User ... var user = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: false, checkCanLoginPolicies: true, checkIsBanned: true); // // Check Password Policies ... await ValidatePasswordPolicies(user, newPassword); // // Clean All User Tokens ... await HandleCleanUserTokens(user); // // Try to Remove User Password ... var removePasswordResult = await UserManager.RemovePasswordAsync(user); if (!removePasswordResult.Succeeded) { XException.ActionFailed.Throw(); } // // try to Add New Password ... var passwordResetResult = await UserManager.AddPasswordAsync(user, newPassword); if (!passwordResetResult.Succeeded) { XException.ActionFailed.Throw(); } // // Prepare Message ... var xMessage = GetPasswordChangedMessage( lang, user.Email, returnUrl); // // Send Message ... try { await MessageProvider.SendMailAsync(xMessage); } catch { } } #endregion // #region Profile Image Actions ... /// /// Add Profile Image to a User /// /// a user identifier /// an specific File to upload, IFormFile /// an instance of XUserProfileDto public async Task AddAvatar( string userSelectByParam, IFormFile file ) { // 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 = xUser.Id, Name = saveResult.FileName, Path = saveResult.FilePath, Thumb = saveResult.Thmbnail, ThumbPath = saveResult.ThmbnailPath, CreationDate = DateTime.UtcNow }; // xUser.Avatars.Add(xProfileImage); var updateResult = await UpdateUserAsync( xUser, checkCanLoginPolicies: false, checkIsBanned: false ); // if (!updateResult.Succeeded) { XException.ActionFailed.Throw(); } // xUser.Avatar = xProfileImage.ThumbPath; updateResult = await UpdateUserAsync( xUser, checkCanLoginPolicies: false, checkIsBanned: false ); // if (!updateResult.Succeeded) { XException.ActionFailed.Throw(); } // var result = await GetUserProfileAsync(userSelectByParam, userSelectByParam); return result; } /// /// Add a Collection of Profile Images to a User /// /// a user identifier /// a collection of Files to upload, IFormFileCollection /// an instance of XUserProfileDto public async Task AddAvatars( string userSelectByParam, IFormFileCollection files ) { // var xUser = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: true, checkCanLoginPolicies: false, checkIsBanned: false, ignoreDisabledUser: true, exception: XException.NotFound.ToException() ); // foreach (var file in files) { // // Handle Saving File and Attach it to User ... var saveResult = await StorageProvider.HandleProfileImageSave(file); // var xProfileImage = new XProfileImage { UserId = xUser.Id, Name = saveResult.FileName, Path = saveResult.FilePath, Thumb = saveResult.Thmbnail, ThumbPath = saveResult.ThmbnailPath, CreationDate = DateTime.UtcNow }; // xUser.Avatars.Add(xProfileImage); } // var updateResult = await UpdateUserAsync( xUser, checkCanLoginPolicies: false, checkIsBanned: false ); // if (!updateResult.Succeeded) { XException.ActionFailed.Throw(); } // var result = await GetUserProfileAsync(userSelectByParam, userSelectByParam); return result; } /// /// Set Specific Profie Image as Current Profile Image /// /// a user identifier /// an integer which reperesent AvatarId to set as current Avatar /// an instance of XUserProfileDto public async Task SetAvatar( string userSelectByParam, int id ) { // ValidationProvider.NotEmpty(userSelectByParam); // var xUser = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: true, checkCanLoginPolicies: false, checkIsBanned: false, ignoreDisabledUser: true, exception: XException.NotFound.ToException() ); // var xProfileImage = xUser.Avatars.FirstOrDefault(pf => pf.Id == id); if (xProfileImage.IsNull()) { XException.NotFound.Throw(); } // xUser.Avatar = xProfileImage.ThumbPath; var updateResult = await UpdateUserAsync( xUser, checkCanLoginPolicies: false, checkIsBanned: false ); // if (!updateResult.Succeeded) { XException.ActionFailed.Throw(); } // var result = await GetUserProfileAsync(userSelectByParam, userSelectByParam); return result; } /// /// Remove a Collection of User's Profile Images /// /// a user identifier /// a comma seperated list of avatarIds to remove /// an instance of XUserProfileDto public async Task RemoveAvatar( string userSelectByParam, ICollection ids ) { // ValidationProvider.NotEmpty(userSelectByParam); // var xUser = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: true, checkCanLoginPolicies: false, checkIsBanned: false, ignoreDisabledUser: true, exception: XException.NotFound.ToException() ); // var xProfileImages = xUser.Avatars .Where(pf => ids.Contains(pf.Id)); if (xProfileImages.HasChild()) { // xUser.Avatars = xUser.Avatars .Except(xProfileImages) .ToList(); // // Creat a List of Physical Files to Remove ... var xFilePathsForRemove = xProfileImages.Select(pf => pf.Thumb).ToList(); xFilePathsForRemove.AddRange(xProfileImages.Select(pf => pf.Name)); // StorageProvider.DeleteFiles( xFilePathsForRemove, forceFileExists: false); // var isCurrentProfileImage = xProfileImages.Any(pfi => pfi.ThumbPath == xUser.Avatar); if (isCurrentProfileImage) { xUser.Avatar = ""; } // await UpdateUserAsync(xUser); } // var result = await GetUserProfileAsync(userSelectByParam, userSelectByParam); return result; } #endregion // #region Confirmations ... /// /// Confirm Registration /// /// specify destination language /// an instance of XDevice /// a token which approved user action /// redirection url /// public async Task ConfirmRegistration( string lang, XDevice device, string actionToken, string returnUrl ) { // // Validate Args ... await ValidationProvider .GroupValidationBuilder() .AddNotEmpty( lang, actionToken, returnUrl) .AddNotNull(device) .ValidateGroupAsync(); // // Check Device Validation ... await ValidateDeviceForActions(device); // // Get Related Token to Registration Hash and Validate it, // then Parse XActionRequest Instance from Token ... var request = await ValidateAndParseActionHash(actionToken); if (request.Action != XAction.Finish) { XException.ActionFailed.Throw(); } // // Extract UserSelectByParam from XActionRequest ... var userSelectByParam = GetUserSelectByParam( request, forceNotNull: true); // // Validate user and Retrieve it ... var user = await ValidateUserExistsAndRetrieve( userSelectByParam, containDetails: false, checkCanLoginPolicies: false, ignoreDisabledUser: true, checkIsBanned: true); // // Make User Enabled ... var xMessage = GetRegistrationFinishedMessage( lang, user.Email, returnUrl); // user.IsEnable = true; user.EmailConfirmed = true; // await UpdateUserAsync( user, checkCanLoginPolicies: false, checkIsBanned: false ); // // Remove Token ... await RemoveTokenByHash(actionToken); // // Remove All Prevoius Requests ... await HandleRemoveExistsTokens(user.Id); // await RemoveVerificationCodeRequestByDevice(device); // // Send Mail ... try { await MessageProvider.SendMailAsync(xMessage); } catch { } } /// /// Confirm Mobile Number /// /// specify destination language /// an instance of XDevice /// a token which approved user action /// recieved verification code /// an instance of XActionResponse public async Task ConfirmMobileNumber( string lang, XDevice device, string actionToken, string verificationCode ) { // // Validate Args ... await ValidationProvider .GroupValidationBuilder() .AddNotEmpty(lang, actionToken, verificationCode) .AddNotNull(device) .ValidateGroupAsync(); // // Check Device Validation ... await ValidateDeviceForActions(device); // // Get Related Token to Registration Hash and Validate it, // then Parse XActionRequest Instance from Token ... var request = await ValidateAndParseActionHash(actionToken); ValidationProvider.MobileNumber(request.Context.MobileNumber); // // Validate two Device Must Same ... ValidateRequestAndGiveDevices(device, request.Context.Device); // // Check XActionRequest Action Must be Request Mobile Validation ... if (request.Action != XAction.RequestMobileVerificationCode) { XException.InvalidData.Throw(); } // // Extract UserSelectByParam from XActionRequest ... var userSelectByParam = GetUserSelectByParam(request); // // since device must Requested before, // Retrieve XVerification instance by Verification Code from Db // and Validate it ... XVerificationRequest xVerificationRequest = await ValidateAndRetrieveVerificationRequest(verificationCode); // // Check User Added To Db or Not ... // var isUserExists = await IsUserExistsAsync(userSelectByParam); 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); // // Update Exists User's Mobile Confirmation ... user.PhoneNumberConfirmed = true; // // Save Changes to Db ... await UpdateUserAsync(user, checkCanLoginPolicies: false, checkIsBanned: false); // request.Context.UserId = user.Id; } // // Update Request Context MobileNumber Verification Code // and it's Confirmation Status ... request.Context.MobileVerificationCode = verificationCode; request.Context.MobileVerified = true; // // Prepare New Token Result , // by Requesting an Action ... var result = await ActionRequest( lang, device, userSelectByParam, XAction.ConfirmMobileNumber, request.Context, forceCheckUserExists: isAddedUser ); // // Remove Previous Token ... await RemoveTokenByHash(actionToken); try { // // Remove XVerificationRequest instance from Db ... await RemoveVerificationRequest(verificationCode); } catch { } // // Return Result ... return result; } /// /// Confirm Email Address /// /// specify destination language /// an instance of XDevice /// a token which approved user action /// recieved verification code /// an instance of XActionResponse public async Task ConfirmEmailAddress( string lang, XDevice device, string actionToken, string verificationCode ) { // // Validate Args ... await ValidationProvider .GroupValidationBuilder() .AddNotEmpty(lang, actionToken, verificationCode) .AddNotNull(device) .ValidateGroupAsync(); // // Check Device Validation ... await ValidateDeviceForActions(device); // // Get Related Token to Registration Hash and Validate it, // then Parse XActionRequest Instance from Token ... var request = await ValidateAndParseActionHash(actionToken); ValidationProvider.EmailAddress(request.Context.Email); // // Validate two Device Must Same ... ValidateRequestAndGiveDevices(device, request.Context.Device); // // Check XActionRequest Action Must be Request Mobile Validation ... if (request.Action != XAction.RequestEmailVerificationCode) { XException.InvalidData.Throw(); } // // Extract UserSelectByParam from XActionRequest ... var userSelectByParam = GetUserSelectByParam(request); // // since device must Requested before, // Retrieve XVerification instance by Verification Code from Db // and Validate it ... XVerificationRequest xVerificationRequest = await ValidateAndRetrieveVerificationRequest(verificationCode); // // 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); // // Update Exists User's Email Confirmation ... user.EmailConfirmed = true; // // Save Changes to Db ... await UpdateUserAsync(user, checkCanLoginPolicies: false, checkIsBanned: false); // request.Context.UserId = user.Id; } // // Update Request Context Email Address Verification Code // and it's Confirmation Status ... request.Context.EmailVerificationCode = verificationCode; request.Context.EmailVerified = true; // // Prepare New Token Result , // by Requesting an Action ... var result = await ActionRequest( lang, device, userSelectByParam, XAction.ConfirmEmailAddress, request.Context, forceCheckUserExists: isAddedUser ); // // Remove Previous Token ... await RemoveTokenByHash(actionToken); // // Remove XVerificationRequest instance from Db ... await RemoveVerificationRequest(verificationCode); // // Return Result ... return result; } #endregion } }