irc-netcore-api/IRaCIS.Core.Application/Service/Management/UserService.cs

611 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using IRaCIS.Application.Contracts;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Mvc;
using Panda.DynamicWebApi.Attributes;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
namespace IRaCIS.Application.Services
{
[ApiExplorerSettings(GroupName = "Management")]
public class UserService : BaseService, IUserService
{
private readonly IRepository<User> _userRepository;
private readonly IMailVerificationService _mailVerificationService;
private readonly IRepository<VerificationCode> _verificationCodeRepository;
private readonly IRepository<Doctor> _doctorRepository;
private readonly IRepository<TrialUser> _userTrialRepository;
private readonly IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig;
public UserService(IRepository<User> userRepository,
IMailVerificationService mailVerificationService,
IRepository<VerificationCode> verificationCodeRepository,
IRepository<Doctor> doctorRepository,
IRepository<TrialUser> userTrialRepository,
IOptionsMonitor<ServiceVerifyConfigOption> verifyConfig
)
{
_verifyConfig = verifyConfig;
_userRepository = userRepository;
_mailVerificationService = mailVerificationService;
_verificationCodeRepository = verificationCodeRepository;
_doctorRepository = doctorRepository;
_userTrialRepository = userTrialRepository;
}
private async Task VerifyUserNameAsync(Guid? userId, string userName)
{
if (await _userRepository.WhereIf(userId!=null,t=>t.Id!=userId).AnyAsync(t => t.UserName == userName ))
{
throw new BusinessValidationFailedException("用户名已经存在。");
}
}
private async Task VerifyUserPhoneAsync(Guid? userId, Guid userTypeId, string phone)
{
if (await _userRepository.WhereIf(userId != null, t => t.Id != userId).AnyAsync(t => (t.Phone == phone && t.UserTypeId == userTypeId )))
{
throw new BusinessValidationFailedException("该用户类型中已存在具有相同的电话的用户。");
}
}
private async Task VerifyUserEmailAsync(Guid? userId, Guid userTypeId, string email)
{
if (await _userRepository.WhereIf(userId != null, t => t.Id != userId).AnyAsync(t => (t.EMail == email && t.UserTypeId == userTypeId)))
{
throw new BusinessValidationFailedException("该用户类型中已存在具有相同邮箱的用户。");
}
}
private async Task VerifyUserPwdAsync(Guid userId, string newPwd, string? oldPwd = null)
{
//var dbUser = (await _userRepository.FirstOrDefaultAsync(t => t.Id == userId)).IfNullThrowException();
if (_verifyConfig.CurrentValue.OpenUserComplexPassword)
{
if (oldPwd != null && oldPwd == newPwd)
{
throw new BusinessValidationFailedException("新密码与旧密码相同。");
}
var dbUser = (await _userRepository.FirstOrDefaultAsync(t => t.Id == userId)).IfNullThrowException();
if (oldPwd != null && dbUser.Password != oldPwd)
{
throw new BusinessValidationFailedException("旧密码验证失败。");
}
if (dbUser.Password == newPwd)
{
throw new BusinessValidationFailedException("新密码与旧密码相同。");
}
//正则 至少8个字符至少1个大写字母1个小写字母1个数字和1个特殊字符
//^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}
if (!Regex.IsMatch(newPwd, @"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[_.@])[A-Za-z0-9_.@$!%*?&]{10,}"))
{
throw new BusinessValidationFailedException("密码至少10个字符且包括至少1个大写字母1个小写字母1个数字和1个特殊字符");
}
}
await Task.CompletedTask;
}
/// <summary>发送验证码 修改邮箱(已经登陆修改) New </summary>
[HttpGet("{email}")]
public async Task<IResponseOutput> SendVerificationCode(string email)
{
//检查手机或者邮箱是否有效
if (!Regex.IsMatch(email, @"^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$"))
{
return ResponseOutput.NotOk("Please input a legal email");
}
//验证码 6位
int verificationCode = new Random().Next(100000, 1000000);
await _mailVerificationService.SendMailEditEmail(_userInfo.Id, _userInfo.RealName, email, verificationCode);
return ResponseOutput.Ok();
}
[HttpPut("{newEmail}/{verificationCode}")]
public async Task<IResponseOutput> SetNewEmail(string newEmail, string verificationCode)
{
var verificationRecord = await _verificationCodeRepository
.FirstOrDefaultAsync(t => t.UserId == _userInfo.Id && t.Code == verificationCode && t.CodeType == 0);
//检查数据库是否存在该验证码
if (verificationRecord == null)
{
return ResponseOutput.NotOk("验证码错误。");
}
else
{
//检查验证码是否失效
if (verificationRecord.ExpirationTime < DateTime.Now)
{
return ResponseOutput.NotOk("验证码已经过期。");
}
else //验证码正确 并且 没有超时
{
//更新密码
//var pwd = MD5Helper.Md5(newPwd);
//var count = _doctorRepository.Update<Doctor>().Where(t => t.Id == doctor.Id).Set(d => d.Password == pwd).ExecuteAffrows();
await VerifyUserEmailAsync(_userInfo.Id, _userInfo.UserTypeId, newEmail);
await _userRepository.UpdatePartialNowNoQueryAsync(_userInfo.Id, u => new User()
{
EMail = newEmail
});
//删除验证码历史记录
await _verificationCodeRepository.BatchDeleteNoTrackingAsync(t => t.UserId == _userInfo.Id && t.CodeType == 0);
return ResponseOutput.Ok();
}
}
}
[HttpPut("{newPhone}")]
public async Task<IResponseOutput> SetNewPhone(string newPhone)
{
await VerifyUserPhoneAsync(_userInfo.Id, _userInfo.UserTypeId, newPhone);
await _userRepository.UpdatePartialNowNoQueryAsync(_userInfo.Id, u => new User()
{
Phone = newPhone
});
return ResponseOutput.Ok();
}
[HttpPut("{newUserName}")]
public async Task<IResponseOutput> SetNewUserName(string newUserName)
{
await VerifyUserNameAsync(_userInfo.Id, newUserName);
await _userRepository.UpdatePartialNowNoQueryAsync(_userInfo.Id, u => new User()
{
UserName = newUserName
});
return ResponseOutput.Ok();
}
[HttpGet]
public async Task<IResponseOutput> InitSetUserNameAndPwd(Guid userId, string newUserName, string newPWd)
{
await VerifyUserPwdAsync(userId, newPWd);
await VerifyUserNameAsync(userId, newUserName);
await _userRepository.UpdatePartialFromQueryAsync(userId, u => new User()
{
UserName = newUserName,
Password = newPWd,
IsFirstAdd = false,
}, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 重置密码为 默认密码
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
[HttpGet("{userId:guid}")]
public async Task<IResponseOutput> ResetPassword(Guid userId)
{
await _mailVerificationService.AdminResetPwdSendEmailAsync(userId);
await _userRepository.UpdatePartialNowNoQueryAsync(userId, u => new User()
{
Password = MD5Helper.Md5(StaticData.DefaultPassword),
IsFirstAdd = true
});
return ResponseOutput.Ok();
}
/// <summary>
/// 重置密码发邮件 (未登陆修改)
/// </summary>
/// <param name="email"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpGet("{email}")]
public async Task<IResponseOutput> AnonymousSendVerificationCode(string email)
{
//检查手机或者邮箱是否有效
if (!Regex.IsMatch(email, @"^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$"))
{
return ResponseOutput.NotOk("请输入一个正确的邮箱。");
}
////查找改邮箱或者手机的用户
var exist = await _userRepository.AnyAsync(t => t.EMail == email);
if (!exist)
{
return ResponseOutput.NotOk("邮箱错误。");
}
//验证码 6位
int verificationCode = new Random().Next(100000, 1000000);
await _mailVerificationService.AnolymousSendEmailForResetAccount(email, verificationCode);
return ResponseOutput.Ok();
}
/// <summary>
/// 验证验证码,没问题就返回用户所有的账户
/// </summary>
/// <param name="email"></param>
/// <param name="verifyCode"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[AllowAnonymous]
[HttpGet("{email}/{verifyCode}")]
public async Task<List<UserAccountDto>> VerifyAnonymousVerifyCode(string email, string verifyCode)
{
var verificationRecord = await _verificationCodeRepository
.Where(t => t.UserId == Guid.Empty && t.Code == verifyCode && t.CodeType == VerifyType.Email && t.EmailOrPhone == email).OrderByDescending(t => t.CreateTime).FirstOrDefaultAsync();
//检查数据库是否存在该验证码
if (verificationRecord == null)
{
throw new BusinessValidationFailedException("验证码错误。");
}
else
{
//检查验证码是否失效
if (verificationRecord.ExpirationTime < DateTime.Now)
{
throw new BusinessValidationFailedException("验证码已经过期。");
}
else //验证码正确 并且 没有超时
{
//删除验证码历史记录
await _verificationCodeRepository.BatchDeleteNoTrackingAsync(t => t.Id == verificationRecord.Id);
}
}
var list = await _userRepository.Where(t => t.EMail == email).Select(t => new UserAccountDto() { UserId = t.Id, UserName = t.UserName, UserRealName = t.FullName, UserType = t.UserTypeRole.UserTypeShortName }).ToListAsync();
return list;
}
/// <summary>
/// (未登陆) 设置新密码
/// </summary>
/// <param name="userId"></param>
/// <param name="newPwd"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpGet("{userId:guid}/{newPwd}")]
public async Task<IResponseOutput> AnonymousSetPassword(Guid userId, string newPwd)
{
await VerifyUserPwdAsync(userId, newPwd);
var success = await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == userId, u => new User()
{
Password = newPwd,
IsFirstAdd = false
});
return ResponseOutput.Result(success);
}
/// <summary>
/// 修改密码,当前支持旧密码修改密码
/// </summary>
/// <returns></returns>
[HttpPost]
[UnitOfWork]
public async Task<IResponseOutput> ModifyPassword(EditPasswordCommand editPwModel)
{
await VerifyUserPwdAsync(_userInfo.Id, editPwModel.NewPassWord, editPwModel.OldPassWord);
if (!string.IsNullOrEmpty(editPwModel.NewUserName))
{
await VerifyUserNameAsync(_userInfo.Id, editPwModel.NewUserName);
await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == _userInfo.Id, u => new User()
{
UserName = editPwModel.NewUserName,
});
}
var success = await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == _userInfo.Id, u => new User()
{
Password = editPwModel.NewPassWord,
IsFirstAdd = false
});
return ResponseOutput.Result(success);
////医生密码
//if (await _doctorRepository.AnyAsync(t => t.Id == _userInfo.Id && t.Password == editPwModel.OldPassWord))
//{
// var success = await _doctorRepository.BatchUpdateNoTrackingAsync(t => t.Id == _userInfo.Id, u => new Doctor()
// {
// Password = editPwModel.NewPassWord
// });
// return ResponseOutput.Result(success);
//}
//return ResponseOutput.NotOk("Old password is wrong.");
}
/// <summary>
/// 获取用户列表
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<UserListDTO>> GetUserList(UserListQueryDTO param)
{
var userQueryable = _userRepository.Where(x => x.UserTypeEnum != UserTypeEnum.SuperAdmin)
.WhereIf(!string.IsNullOrWhiteSpace(param.UserName), t => t.UserName.Contains(param.UserName) || (t.FullName).Contains(param.UserName))
.WhereIf(!string.IsNullOrWhiteSpace(param.Phone), t => t.Phone.Contains(param.Phone))
.WhereIf(!string.IsNullOrWhiteSpace(param.OrganizationName), t => t.OrganizationName.Contains(param.OrganizationName))
.WhereIf(param.UserType != null, t => t.UserTypeId == param.UserType)
.WhereIf(param.UserState != null, t => t.Status == param.UserState)
.ProjectTo<UserListDTO>(_mapper.ConfigurationProvider);
return await userQueryable.ToPagedListAsync(param.PageIndex, param.PageSize, param.SortField == string.Empty ? "UserName" : param.SortField, param.Asc);
}
/// <summary>
/// 根据用户Id获取用户详细信息[New]
/// </summary>
/// <param name="id"></param>
/// <returns></returns>xiuga
[HttpGet("{id:guid}")]
public async Task<UserDetailDTO> GetUser(Guid id)
{
var userQuery = _userRepository.Where(t => t.Id == id).ProjectTo<UserDetailDTO>(_mapper.ConfigurationProvider);
return await (userQuery.FirstOrDefaultAsync()).IfNullThrowException();
}
/// <summary>
/// 添加用户
/// </summary>
/// <param name="userAddModel"></param>
/// <returns></returns>
[UnitOfWork]
public async Task<IResponseOutput<UserAddedReturnDTO>> AddUser(UserCommand userAddModel)
{
await VerifyUserNameAsync(null, userAddModel.UserName);
await VerifyUserEmailAsync(null, userAddModel.UserTypeId, userAddModel.EMail);
await VerifyUserPhoneAsync(null, userAddModel.UserTypeId, userAddModel.Phone);
var saveItem = _mapper.Map<User>(userAddModel);
saveItem.Code = await _userRepository.Select(t => t.Code).DefaultIfEmpty().MaxAsync() + 1;
saveItem.UserCode = AppSettings.UserCodePrefix + saveItem.Code.ToString("D4");
if (saveItem.IsZhiZhun)
{
saveItem.OrganizationName = "Zhizhun";
}
saveItem.Password = MD5Helper.Md5("123456");
await _userRepository.AddAsync(saveItem);
var success = await _userRepository.SaveChangesAsync();
await _mailVerificationService.AddUserSendEmailAsync(saveItem.Id, userAddModel.RouteUrl);
return ResponseOutput.Result(success, new UserAddedReturnDTO { Id = saveItem.Id, UserCode = saveItem.UserCode });
}
/// <summary>
/// 更新用户
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public async Task<IResponseOutput> UpdateUser(UserCommand model)
{
await VerifyUserNameAsync(model.Id, model.UserName);
await VerifyUserEmailAsync(model.Id, model.UserTypeId, model.EMail);
await VerifyUserPhoneAsync(model.Id, model.UserTypeId, model.Phone);
var user = await _userRepository.FirstOrDefaultAsync(t => t.Id == model.Id);
if (user == null) return Null404NotFound(user);
_mapper.Map(model, user);
if (user.IsZhiZhun)
{
user.OrganizationName = "Zhizhun";
}
var success = await _userRepository.SaveChangesAsync();
return ResponseOutput.Ok(success);
}
/// <summary>
/// 删除用户
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
[HttpDelete("{userId:guid}")]
public async Task<IResponseOutput> DeleteUser(Guid userId)
{
if (await _userTrialRepository.AnyAsync(t => t.Id == userId))
{
return ResponseOutput.NotOk("该用户已经参加项目,不能够删除。");
}
var success = await _userRepository.BatchDeleteNoTrackingAsync(t => t.Id == userId);
return ResponseOutput.Result(success);
}
/// <summary>
/// 禁用或者启用账户
/// </summary>
/// <param name="userId"></param>
/// <param name="state"></param>
/// <returns></returns>
[HttpPost("{userId:guid}/{state:int}")]
public async Task<IResponseOutput> UpdateUserState(Guid userId, UserStateEnum state)
{
var success = await _userRepository.BatchUpdateNoTrackingAsync(u => u.Id == userId, t => new User
{
Status = state
});
return ResponseOutput.Result(success);
}
/// <summary>
/// 用户登陆
/// </summary>
/// <param name="userName"></param>
/// <param name="password"></param>
/// <returns></returns>
[NonDynamicMethod]
public async Task<IResponseOutput<LoginReturnDTO>> Login(string userName, string password)
{
var userLoginReturnModel = new LoginReturnDTO();
var loginUser = await _userRepository.Where(u => u.UserName.Equals(userName) && u.Password == password).ProjectTo<UserBasicInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
if (loginUser == null)
{
//此处下面 代码 为了支持医生也能登录 而且前端不加选择到底是管理用户 还是医生用户 奇怪的需求 无法理解
var loginDoctor = await _doctorRepository.Where(u => u.Phone == userName && u.Password == password).ProjectTo<UserBasicInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
if (loginDoctor == null)
{
return ResponseOutput.NotOk("请检查用户名或者密码。", new LoginReturnDTO());
}
userLoginReturnModel.BasicInfo = loginDoctor;
return ResponseOutput.Ok(userLoginReturnModel);
}
if (loginUser.Status == 0)
{
return ResponseOutput.NotOk("该用户已经被禁用。", new LoginReturnDTO());
}
userLoginReturnModel.BasicInfo = loginUser;
return ResponseOutput.Ok(userLoginReturnModel);
}
}
}