using Microsoft.AspNetCore.Identity; using Raven.Client.Documents; using Raven.Client.Documents.Linq; using Raven.Client.Documents.Session; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using zero.Core.Collections; using zero.Core.Entities; using zero.Core.Extensions; namespace zero.Core.Api { public class UserApi : BackofficeApi, IUserApi { protected UserManager UserManager { get; private set; } public UserApi(ICollectionContext store, UserManager userManager) : base(store, isCoreDatabase: true) { UserManager = userManager; } /// public async Task GetUserById(string id) { BackofficeUser user = await UserManager.FindByIdAsync(id); return user; } /// public async Task GetUserByEmail(string email) { BackofficeUser user = await UserManager.FindByEmailAsync(email); return user; } /// public async Task> GetByIds(params string[] ids) { return await GetByIds(ids); } /// public async Task> GetAll() { return await Session.Query() .OrderByDescending(x => x.CreatedDate) .ToListAsync(); } /// public async Task> GetByQuery(ListQuery query) { string currentUserId = UserManager.GetUserId(Context.Context.BackofficeUser); query.SearchSelector = user => user.Name; return await Session.Query() .ToQueriedListAsync(query); } /// public async Task> Save(BackofficeUser model) { bool updateSecurityStamp = false; if (!model.Id.IsNullOrEmpty()) { BackofficeUser origin = await GetUserById(model.Id); updateSecurityStamp = origin != null && model.PasswordHash != origin.PasswordHash; } EntityResult result = await SaveModel(model); //, new UserValidator()); if (updateSecurityStamp) { await UserManager.UpdateSecurityStampAsync(model); } return result; } /// public async Task> Delete(string id) { return await DeleteById(id); } /// public async Task> HashPassword(BackofficeUser user, string currentPassword, string newPassword, string confirmNewPassword) { if (newPassword != confirmNewPassword) { return EntityResult.Fail(nameof(newPassword), "@errors.changepassword.newpasswordsnotmatching"); } if (currentPassword.IsNullOrWhiteSpace() || newPassword.IsNullOrWhiteSpace()) { return EntityResult.Fail(nameof(currentPassword), "@errors.changepassword.emptyfields"); } if (user == null) { return EntityResult.Fail("@errors.changepassword.nouser"); } if (UserManager.PasswordHasher.VerifyHashedPassword(user, user.PasswordHash, currentPassword) != PasswordVerificationResult.Success) { return EntityResult.Fail("@errors.changepassword.passwordincorrect"); } // validate new password List errors = new(); bool isValid = true; foreach (var v in UserManager.PasswordValidators) { var result = await v.ValidateAsync(UserManager, user, newPassword); if (!result.Succeeded) { if (result.Errors.Any()) { errors.AddRange(result.Errors); } isValid = false; } } if (!isValid) { EntityResult result = EntityResult.Fail(); foreach (IdentityError error in errors) { result.AddError(error.Description); } return result; } return EntityResult.Success(UserManager.PasswordHasher.HashPassword(user, newPassword)); } /// public async Task> UpdatePassword(BackofficeUser user, string currentPassword, string newPassword) { if (currentPassword.IsNullOrWhiteSpace() || newPassword.IsNullOrWhiteSpace()) { return EntityResult.Fail(nameof(currentPassword), "@errors.changepassword.emptyfields"); } if (user == null) { return EntityResult.Fail("@errors.changepassword.nouser"); } IdentityResult identityResult = await UserManager.ChangePasswordAsync(user as BackofficeUser, currentPassword, newPassword); if (!identityResult.Succeeded) { EntityResult result = EntityResult.Fail(); foreach (IdentityError error in identityResult.Errors) { result.AddError(error.Description); } return result; } return EntityResult.Success(user); } /// public async Task> Enable(BackofficeUser user) { return await UpdateActiveState(user, true); } /// public async Task> Disable(BackofficeUser user) { return await UpdateActiveState(user, false); } /// /// Updates the active state of user. /// If IsActive=false, the user cannot login anymore /// async Task> UpdateActiveState(BackofficeUser user, bool isActive) { user.IsActive = isActive; IdentityResult identityResult = await UserManager.UpdateAsync(user as BackofficeUser); if (!identityResult.Succeeded) { EntityResult result = EntityResult.Fail(); foreach (IdentityError error in identityResult.Errors) { result.AddError(error.Description); } return result; } await UserManager.UpdateSecurityStampAsync(user as BackofficeUser); return EntityResult.Success(user); } } public interface IUserApi : IBackofficeApi { /// /// Find user by id /// Task GetUserById(string id); /// /// Find user by email /// Task GetUserByEmail(string email); /// /// Get users by ids /// Task> GetByIds(params string[] ids); /// /// Get all users for the selected application /// Task> GetAll(); /// /// Get all available users (with query) /// Task> GetByQuery(ListQuery query); /// /// Creates or updates a user /// Task> Save(BackofficeUser model); /// /// Deletes a user /// Task> Delete(string id); /// /// Changes the password of the current user. /// User is logged out if this operation succeeds. /// Task> UpdatePassword(BackofficeUser user, string currentPassword, string newPassword); /// /// Tries to hash a new password /// Task> HashPassword(BackofficeUser user, string currentPassword, string newPassword, string confirmNewPassword); /// /// Enables a user /// Task> Enable(BackofficeUser user); /// /// Disables a user /// Task> Disable(BackofficeUser user); } }