using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using StopShopping.EF; using StopShopping.Services.Extensions; using StopShopping.Services.Models; using StopShopping.Services.Models.Req; using StopShopping.Services.Models.Resp; namespace StopShopping.Services.Implementions; public class UserService : IUserService { public UserService( ILogger logger, StopShoppingContext dbContext, ICipherService cipherService, IAccessTokenService accessTokenService, IClaimsService claimsService, IFileService fileService, ISerialNoGenerator serialNoGenerator) { _logger = logger; _dbContext = dbContext; _cipherService = cipherService; _accessTokenService = accessTokenService; _claimsService = claimsService; _fileService = fileService; _serialNoGenerator = serialNoGenerator; } private readonly ILogger _logger; private readonly StopShoppingContext _dbContext; private readonly ICipherService _cipherService; private readonly IAccessTokenService _accessTokenService; private readonly IClaimsService _claimsService; private readonly IFileService _fileService; private readonly ISerialNoGenerator _serialNoGenerator; public async Task SignUpAsync(SignUpParams model) { var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Account == model.Account); if (null != user) return ApiResponse.Failed("帐户名已存在"); user = new EF.Models.User { Account = model.Account!, Addresses = [], Avatar = Consts.DEFAULT_AVATAR, CurrentRole = model.DefaultRole.GetValue(), NickName = model.NickName!, Password = _cipherService.EncryptUserPassword(model.Password!) }; await _dbContext.AddAsync(user); if (await _dbContext.SaveChangesAsync() > 0) return ApiResponse.Succed(); return ApiResponse.Failed("数据库操作失败"); } public async Task> SignInAsync(SignInParams model) { SignInResult result = new(); var user = await _dbContext.Users .FirstOrDefaultAsync(u => u.Account == model.Account); if (null == user || user.Password != _cipherService.EncryptUserPassword(model.Password!)) { result.IsSucced = false; result.Message = "账号或密码错误"; return result; } user.LastLoginTime = DateTime.Now; await _dbContext.SaveChangesAsync(); var claimsIdentity = _claimsService.BuildIdentity(user); result.RefreshToken = await _accessTokenService.SetRefreshTokenAsync(user.Id, SystemRoles.User); result.User = new SignInUser { AvatarUrl = string.IsNullOrWhiteSpace(user.Avatar) ? null : _fileService.GetFileUrl(UploadScences.Avatar, user.Avatar), NickName = user.NickName, DefaultRole = user.CurrentRole.ToUserRoles(), AccessToken = _accessTokenService.GenerateAccessToken(claimsIdentity) }; return result; } public async Task> SignInAdminAsync(SignInParams model) { SignInResult result = new(); var admin = await _dbContext.Administrators .FirstOrDefaultAsync(u => u.Account == model.Account); if (null == admin || admin.Password != _cipherService.EncryptUserPassword(model.Password!)) { result.IsSucced = false; result.Message = "账号或密码错误"; return result; } admin.LastLoginTime = DateTime.Now; await _dbContext.SaveChangesAsync(); var claimsIdentity = _claimsService.BuildAdminIdentity(admin); result.RefreshToken = await _accessTokenService.SetRefreshTokenAsync(admin.Id, SystemRoles.Admin); result.User = new SignInAdmin { NickName = admin.NickName, AccessToken = _accessTokenService.GenerateAccessToken(claimsIdentity) }; return result; } public async Task GenerateDefaultAdminAsync() { var defaultAdmin = await _dbContext.Administrators .Where(a => a.Account == Consts.DEFAULT_ADMIN_ACCOUNT) .FirstOrDefaultAsync(); if (null != defaultAdmin) { _logger.LogInformation("默认管理员已存在,已跳过"); return; } var pwd = _serialNoGenerator.GenerateRandomPassword(); defaultAdmin = new() { Account = Consts.DEFAULT_ADMIN_ACCOUNT, NickName = "超级管理员", Password = _cipherService.EncryptUserPassword(pwd) }; await _dbContext.Administrators.AddAsync(defaultAdmin); await _dbContext.SaveChangesAsync(); _logger.LogInformation( "默认管理员({Account})已生成,请立马修改密码:{Password}", Consts.DEFAULT_ADMIN_ACCOUNT, pwd); } public async Task ChangePasswordAsync(ChangePasswordParams model) { int userId = _claimsService.GetCurrentUserId(); var user = await _dbContext.Users .FirstAsync(u => u.Id == userId); if (_cipherService.EncryptUserPassword(model.OldPassword!) != user.Password) return ApiResponse.Failed("原密码错误"); user.Password = _cipherService.EncryptUserPassword(model.NewPassword!); await _dbContext.SaveChangesAsync(); return ApiResponse.Succed(); } public async Task> GetUserInfoAsync() { var userId = _claimsService.GetCurrentUserId(); var model = await _dbContext.Users .FirstAsync(u => u.Id == userId); User user = new() { Account = model.Account, AvatarUrl = string.IsNullOrWhiteSpace(model.Avatar) ? null : _fileService.GetFileUrl(UploadScences.Avatar, model.Avatar), DefaultRole = model.CurrentRole.ToUserRoles(), LastLoginTime = model.LastLoginTime?.ToFormatted(), NickName = model.NickName, Telephone = model.Telephone }; return new ApiResponse(user); } public async Task EditAsync(EditUserParams model) { int userId = _claimsService.GetCurrentUserId(); var user = await _dbContext.Users.FirstAsync(u => u.Id == userId); if (!string.IsNullOrWhiteSpace(model.AvatarFileName)) user.Avatar = model.AvatarFileName; user.CurrentRole = model.DefaultRole.GetValue(); if (!string.IsNullOrWhiteSpace(model.NickName)) user.NickName = model.NickName; if (!string.IsNullOrWhiteSpace(model.Telephone)) user.Telephone = model.Telephone; await _dbContext.SaveChangesAsync(); return ApiResponse.Succed(); } public ApiResponse> GetAddresses() { var userId = _claimsService.GetCurrentUserId(); var addresses = _dbContext.Addresses .Where(a => a.UserId == userId) .OrderByDescending(a => a.Default) .AsNoTracking() .Select(Cast) .ToList(); return new ApiResponse>(addresses); } public async Task EditAddressAsync(EditAddressParams model) { EF.Models.Address? address = null; var userId = _claimsService.GetCurrentUserId(); if (model.Id.HasValue && model.Id > 0) { address = await _dbContext.Addresses .FirstOrDefaultAsync(a => a.Id == model.Id && a.UserId == userId); if (null == address) return ApiResponse.Failed("地址已不存在"); } else { address = new(); await _dbContext.Addresses.AddAsync(address); } address.Default = model.Default; address.Detail = model.Detail; address.DistrictLevel1Id = model.DistrictLevel1Id; address.DistrictLevel2Id = model.DistrictLevel2Id; address.DistrictLevel3Id = model.DistrictLevel3Id; address.DistrictLevel4Id = model.DistrictLevel4Id; address.Name = model.Name; address.Tag = model.Tag; address.Telephone = model.Telephone; await _dbContext.SaveChangesAsync(); return ApiResponse.Succed(); } public async Task DeleteAddressAsync(int id) { var userId = _claimsService.GetCurrentUserId(); await _dbContext.Addresses .Where(a => a.Id == id && a.UserId == userId) .ExecuteDeleteAsync(); return ApiResponse.Succed(); } #region private methods private Address Cast(EF.Models.Address a) { return new Address { Default = a.Default, Detail = a.Detail, DistrictLevel1Id = a.DistrictLevel1Id, DistrictLevel2Id = a.DistrictLevel2Id, DistrictLevel3Id = a.DistrictLevel3Id, DistrictLevel4Id = a.DistrictLevel4Id, Id = a.Id, Name = a.Name, Tag = a.Tag, Telephone = a.Telephone }; } #endregion }