using IRaCIS.Core.Domain.Share; using MimeKit; using IRaCIS.Core.Application.Helper; using MailKit; using Microsoft.AspNetCore.Hosting; using IRaCIS.Core.Application.Auth; using AutoMapper; using IRaCIS.Application.Contracts; using Nito.AsyncEx; using Microsoft.Extensions.Options; namespace IRaCIS.Application.Services { public interface IMailVerificationService { Task AnolymousSendEmail(string researchProgramNo, string emailAddress, int verificationCode); Task SendEmailVerification(string emailAddress, int verificationCode); Task SiteSurveyRejectEmail(MimeMessage messageToSend); Task SendMailEditEmail(Guid userId, string userName, string emailAddress, int verificationCode); Task AnolymousSendEmailForResetAccount(string emailAddress, int verificationCode); Task AddUserSendEmailAsync(Guid userId, string baseUrl, string routeUrl); Task AdminResetPwdSendEmailAsync(Guid userId, string pwdNotMd5 = "123456"); Task SiteSurveyUserJoinEmail(Guid trialId, Guid userId, string baseUrl, string rootUrl); Task ExternalUserJoinEmail(Guid trialId, Guid userId, string baseUrl, string rootUrl); Task DoctorJoinTrialEmail(Guid trialId, Guid doctorId, string baseUrl, string rootUrl); } public class MailVerificationService : IMailVerificationService { private readonly IRepository _verificationCodeRepository; private readonly IRepository _systemBasicDatarepository; private readonly IWebHostEnvironment _hostEnvironment; private readonly IRepository _userRepository; private readonly ITokenService _tokenService; private readonly IMapper _mapper; private readonly IRepository _trialRepository; private readonly IRepository _userTypeRepository; private readonly IRepository _doctorTypeRepository; private readonly AsyncLock _mutex = new AsyncLock(); private readonly SystemEmailSendConfig _systemEmailConfig; public MailVerificationService(IRepository verificationCodeRepository, IRepository systemBasicDatarepository, IWebHostEnvironment hostEnvironment, IRepository userRepository, ITokenService tokenService, IRepository trialRepository, IRepository userTypeRepository, IRepository doctorTypeRepository, IMapper mapper, IOptionsMonitor systemEmailConfig) { _systemEmailConfig = systemEmailConfig.CurrentValue; _verificationCodeRepository = verificationCodeRepository; _systemBasicDatarepository = systemBasicDatarepository; _hostEnvironment = hostEnvironment; _mapper = mapper; _tokenService = tokenService; _userRepository = userRepository; _trialRepository = trialRepository; _userTypeRepository = userTypeRepository; _doctorTypeRepository = doctorTypeRepository; } //重置邮箱 public async Task SendMailEditEmail(Guid userId, string userName, string emailAddress, int verificationCode) { var messageToSend = new MimeMessage(); //发件地址 messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail)); //收件地址 messageToSend.To.Add(new MailboxAddress(userName, emailAddress)); //主题 messageToSend.Subject = "[来自展影IRC] 关于重置邮箱的提醒"; var builder = new BodyBuilder(); var pathToFile = _hostEnvironment.WebRootPath + Path.DirectorySeparatorChar.ToString() + "EmailTemplate" + Path.DirectorySeparatorChar.ToString() + "UserOptCommon.html"; using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile)) { var templateInfo = SourceReader.ReadToEnd(); builder.HtmlBody = string.Format(templateInfo, $" 尊敬的 {userName} , ", "您正在进行邮箱重置操作", verificationCode ); } messageToSend.Body = builder.ToMessageBody(); EventHandler sucessHandle = (sender, args) => { // args.Response var code = verificationCode.ToString(); _ = _verificationCodeRepository.AddAsync(new VerificationCode() { CodeType = 0, HasSend = true, Code = code, UserId = userId, ExpirationTime = DateTime.Now.AddMinutes(3) }).Result; _ = _verificationCodeRepository.SaveChangesAsync().Result; }; await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, sucessHandle); } //不登录 通过邮箱重置密码 public async Task AnolymousSendEmailForResetAccount(string emailAddress, int verificationCode) { var messageToSend = new MimeMessage(); //发件地址 messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail)); //收件地址 messageToSend.To.Add(new MailboxAddress(String.Empty, emailAddress)); //主题 messageToSend.Subject = "[来自展影IRC] 关于重置密码的提醒"; var builder = new BodyBuilder(); var pathToFile = _hostEnvironment.WebRootPath + Path.DirectorySeparatorChar.ToString() + "EmailTemplate" + Path.DirectorySeparatorChar.ToString() + "UserOptCommon.html"; using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile)) { var templateInfo = SourceReader.ReadToEnd(); builder.HtmlBody = string.Format(templateInfo, "", "您正在进行邮箱重置密码操作", verificationCode ); } messageToSend.Body = builder.ToMessageBody(); EventHandler sucessHandle = (sender, args) => { var code = verificationCode.ToString().Trim(); _ = _verificationCodeRepository.AddAsync(new VerificationCode() { CodeType = Core.Domain.Share.VerifyType.Email, HasSend = true, Code = code, UserId = Guid.Empty,//此时不知道用户 EmailOrPhone = emailAddress, ExpirationTime = DateTime.Now.AddMinutes(3) }).Result; _ = _verificationCodeRepository.SaveChangesAsync().Result; }; await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, sucessHandle); } /// /// 发送验证码 /// /// /// /// public async Task SendEmailVerification(string emailAddress, int verificationCode) { var messageToSend = new MimeMessage(); //发件地址 messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail)); //收件地址 messageToSend.To.Add(new MailboxAddress(String.Empty, emailAddress)); //主题 messageToSend.Subject = $"[来自展影IRC]的提醒"; var builder = new BodyBuilder(); var pathToFile = _hostEnvironment.WebRootPath + Path.DirectorySeparatorChar.ToString() + "EmailTemplate" + Path.DirectorySeparatorChar.ToString() + "UserOptCommon.html"; using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile)) { var templateInfo = SourceReader.ReadToEnd(); builder.HtmlBody = string.Format(templateInfo, "", "您正在参与展影医疗IRC项目", verificationCode ); } messageToSend.Body = builder.ToMessageBody(); EventHandler sucessHandle = (sender, args) => { // args.Response var code = verificationCode.ToString(); _ = _verificationCodeRepository.AddAsync(new VerificationCode() { CodeType = VerifyType.Email, HasSend = true, Code = code, UserId = Guid.Empty,//此时不知道用户 EmailOrPhone = emailAddress, ExpirationTime = DateTime.Now.AddMinutes(3) }).Result; _ = _verificationCodeRepository.SaveChangesAsync().Result; }; await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, sucessHandle); } //中心调研 登陆 public async Task AnolymousSendEmail(string researchProgramNo, string emailAddress, int verificationCode) { var messageToSend = new MimeMessage(); //发件地址 messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail)); //收件地址 messageToSend.To.Add(new MailboxAddress(String.Empty, emailAddress)); //主题 messageToSend.Subject = $"[来自展影IRC] [{researchProgramNo}] 关于中心调研的提醒"; var builder = new BodyBuilder(); var pathToFile = _hostEnvironment.WebRootPath + Path.DirectorySeparatorChar.ToString() + "EmailTemplate" + Path.DirectorySeparatorChar.ToString() + "UserOptCommon.html"; using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile)) { var templateInfo = SourceReader.ReadToEnd(); builder.HtmlBody = string.Format(templateInfo, "", "您正在参与展影医疗IRC项目中心调研工作", verificationCode ); } messageToSend.Body = builder.ToMessageBody(); EventHandler sucessHandle = (sender, args) => { // args.Response var code = verificationCode.ToString(); _ = _verificationCodeRepository.AddAsync(new VerificationCode() { CodeType = VerifyType.Email, HasSend = true, Code = code, UserId = Guid.Empty,//此时不知道用户 EmailOrPhone = emailAddress, ExpirationTime = DateTime.Now.AddMinutes(3) }).Result; _ = _verificationCodeRepository.SaveChangesAsync().Result; }; await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig,sucessHandle); } public async Task SiteSurveyRejectEmail(MimeMessage messageToSend) { //发件地址 messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail)); await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig); } //添加用户发送邮件 public async Task AddUserSendEmailAsync(Guid userId, string baseUrl, string routeUrl) { var sysUserInfo = (await _userRepository.Where(t => t.Id == userId).Include(t => t.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException(); var messageToSend = new MimeMessage(); //发件地址 messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail)); //收件地址 messageToSend.To.Add(new MailboxAddress(sysUserInfo.FullName, sysUserInfo.EMail)); //主题 messageToSend.Subject = "[来自展影IRC] 关于创建账户的提醒"; var builder = new BodyBuilder(); var pathToFile = _hostEnvironment.WebRootPath + Path.DirectorySeparatorChar.ToString() + "EmailTemplate" + Path.DirectorySeparatorChar.ToString() + "AdminAddUser.html"; var token = _tokenService.GetToken(IRaCISClaims.Create(_mapper.Map(sysUserInfo))); await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new User() { EmailToken = token }); routeUrl = routeUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&UserName=" + sysUserInfo.UserName + "&UserType=" + sysUserInfo.UserTypeRole.UserTypeShortName + "&access_token=" + token; var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login")); var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}"; using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile)) { var templateInfo = SourceReader.ReadToEnd(); builder.HtmlBody = string.Format(templateInfo, sysUserInfo.FullName, sysUserInfo.UserName, sysUserInfo.UserTypeRole.UserTypeShortName, redirectUrl ); } messageToSend.Body = builder.ToMessageBody(); await SendEmailHelper.SendEmailAsync(messageToSend,_systemEmailConfig); } //管理员重置密码发送邮件 public async Task AdminResetPwdSendEmailAsync(Guid userId, string pwdNotMd5 = "123456") { var sysUserInfo = (await _userRepository.Where(t => t.Id == userId).Include(t => t.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException(); var messageToSend = new MimeMessage(); //发件地址 messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail)); //收件地址 messageToSend.To.Add(new MailboxAddress(sysUserInfo.FullName, sysUserInfo.EMail)); //主题 messageToSend.Subject = "[来自展影IRC] 关于重置账户密码的提醒"; var builder = new BodyBuilder(); var pathToFile = _hostEnvironment.WebRootPath + Path.DirectorySeparatorChar.ToString() + "EmailTemplate" + Path.DirectorySeparatorChar.ToString() + "AdminResetUser.html"; using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile)) { var templateInfo = SourceReader.ReadToEnd(); builder.HtmlBody = string.Format(templateInfo, sysUserInfo.FullName, sysUserInfo.UserName, sysUserInfo.UserTypeRole.UserTypeShortName, pwdNotMd5 ); } messageToSend.Body = builder.ToMessageBody(); await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig); } //Site调研 用户加入项目 public async Task SiteSurveyUserJoinEmail(Guid trialId, Guid userId, string baseUrl, string rootUrl) { var sysUserInfo = (await _userRepository.Where(t => t.Id == userId).Include(t => t.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException(); var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId); var messageToSend = new MimeMessage(); //发件地址 messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail)); //收件地址 messageToSend.To.Add(new MailboxAddress(sysUserInfo.FullName, sysUserInfo.EMail)); //主题 messageToSend.Subject = $"[来自展影IRC] [{trialInfo.ResearchProgramNo}]邀请信"; var builder = new BodyBuilder(); var token = _tokenService.GetToken(IRaCISClaims.Create(_mapper.Map(sysUserInfo))); if (sysUserInfo.IsFirstAdd) { await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new User() { EmailToken = token }); } var pathToFile = _hostEnvironment.WebRootPath + Path.DirectorySeparatorChar.ToString() + "EmailTemplate" + Path.DirectorySeparatorChar.ToString() + (sysUserInfo.IsFirstAdd ? "TrialUserFirstJoin.html" : "TrialUserExistJoin.html"); using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile)) { var templateInfo = SourceReader.ReadToEnd(); var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&UserName=" + sysUserInfo.UserName + "&UserType=" + sysUserInfo.UserTypeRole.UserTypeShortName + "&access_token=" + token; var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login")); var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}"; builder.HtmlBody = string.Format(templateInfo, sysUserInfo.FullName, trialInfo.ExperimentName, trialInfo.ResearchProgramNo, trialInfo.TrialCode, sysUserInfo.UserName, sysUserInfo.UserTypeRole.UserTypeShortName, sysUserInfo.IsFirstAdd ? redirectUrl : baseUrl ); } messageToSend.Body = builder.ToMessageBody(); await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig,null); } //外部用户 加入项目 public async Task ExternalUserJoinEmail(Guid trialId, Guid userId, string baseUrl, string rootUrl) { var trialInfo = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId)).IfNullThrowException(); var sysUserInfo = (await _userRepository.Where(t => t.Id == userId).Include(t => t.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException(); var messageToSend = new MimeMessage(); //发件地址 messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail)); //收件地址 messageToSend.To.Add(new MailboxAddress(String.Empty, sysUserInfo.EMail)); //主题 messageToSend.Subject = $"[来自展影IRC] [{trialInfo.ResearchProgramNo}]邀请信"; var builder = new BodyBuilder(); var token = _tokenService.GetToken(IRaCISClaims.Create(_mapper.Map(sysUserInfo))); if (sysUserInfo.IsFirstAdd) { await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new User() { EmailToken = token }); } var pathToFile = _hostEnvironment.WebRootPath + Path.DirectorySeparatorChar.ToString() + "EmailTemplate" + Path.DirectorySeparatorChar.ToString() + (sysUserInfo.IsFirstAdd ? "TrialUserFirstJoin.html" : "TrialUserExistJoin.html"); using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile)) { var templateInfo = SourceReader.ReadToEnd(); var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login")); var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&UserName=" + sysUserInfo.UserName + "&UserType=" + sysUserInfo.UserTypeRole.UserTypeShortName + "&access_token=" + token; var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}"; builder.HtmlBody = string.Format(templateInfo, sysUserInfo.FullName, trialInfo.ExperimentName, trialInfo.ResearchProgramNo, trialInfo.TrialCode, sysUserInfo.UserName, sysUserInfo.UserTypeRole.UserTypeShortName, sysUserInfo.IsFirstAdd ? redirectUrl : baseUrl ); } messageToSend.Body = builder.ToMessageBody(); await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, null); } //医生生成账号加入 或者已存在账号加入到项目中 public async Task DoctorJoinTrialEmail(Guid trialId, Guid doctorId, string baseUrl, string rootUrl) { var doctor = await _doctorTypeRepository.FindAsync(doctorId); User sysUserInfo = null; var userType = await _userTypeRepository.FirstAsync(t => t.UserTypeEnum == UserTypeEnum.IndependentReviewer); using (await _mutex.LockAsync()) { var isDoctorHaveAccount = await _userRepository.AnyAsync(t => t.DoctorId == doctorId); if (!isDoctorHaveAccount) { var saveItem = new User() { FirstName = doctor.FirstName, LastName = doctor.LastName, EMail = doctor.EMail }; var trialType = await _trialRepository.Where(t => t.Id == trialId).Select(t => t.TrialType).FirstOrDefaultAsync(); if (trialType == TrialType.NoneOfficial) { saveItem.IsTestUser = true; } saveItem.Code = _userRepository.Select(t => t.Code).DefaultIfEmpty().Max() + 1; saveItem.UserCode = AppSettings.GetCodeStr(saveItem.Code, nameof(User)); saveItem.UserName = saveItem.UserCode; saveItem.UserTypeEnum = UserTypeEnum.IndependentReviewer; saveItem.DoctorId = doctorId; saveItem.UserTypeId = userType.Id; var savedUser = await _userRepository.AddAsync(saveItem); //下面获取Token 需要这部分信息 sysUserInfo = savedUser.Clone(); sysUserInfo.UserTypeRole = userType; await _userRepository.SaveChangesAsync(); } else { sysUserInfo = (await _userRepository.Where(t => t.DoctorId == doctorId).Include(t => t.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException(); } } var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId); var messageToSend = new MimeMessage(); //发件地址 messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail)); //收件地址 messageToSend.To.Add(new MailboxAddress(doctor.FullName, doctor.EMail)); //主题 messageToSend.Subject = $"[来自展影IRC] [{trialInfo.ResearchProgramNo}]邀请信"; var builder = new BodyBuilder(); var basicInfo = IRaCISClaims.Create(_mapper.Map(sysUserInfo)); ////第一次添加的时候 注意赋值 //basicInfo.PermissionStr = userType.PermissionStr; //basicInfo.UserTypeShortName = userType.UserTypeShortName; var token = _tokenService.GetToken(basicInfo); if (sysUserInfo.IsFirstAdd) { await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new User() { EmailToken = token }); } var pathToFile = _hostEnvironment.WebRootPath + Path.DirectorySeparatorChar.ToString() + "EmailTemplate" + Path.DirectorySeparatorChar.ToString() + (sysUserInfo.IsFirstAdd ? "TrialDoctorFirstJoin.html" : "TrialDoctorExistJoin.html"); using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile)) { var templateInfo = SourceReader.ReadToEnd(); var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&UserName=" + sysUserInfo.UserName + "&UserType=" + userType.UserTypeShortName + "&access_token=" + token; var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login")); var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}"; builder.HtmlBody = string.Format(templateInfo, sysUserInfo.FullName, trialInfo.ExperimentName, trialInfo.ResearchProgramNo, trialInfo.TrialCode, sysUserInfo.UserName, userType.UserTypeShortName, sysUserInfo.IsFirstAdd ? redirectUrl : baseUrl ); } messageToSend.Body = builder.ToMessageBody(); await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, null); return sysUserInfo.Id; } } }