irc-netcore-api/IRaCIS.Core.Application/Service/Common/MailService.cs

1033 lines
45 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.Application.Auth;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using MailKit;
using MailKit.Net.Imap;
using MailKit.Search;
using MailKit.Security;
using Medallion.Threading;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using MimeKit;
using System.Net.Mail;
using System.Runtime.CompilerServices;
namespace IRaCIS.Core.Application.Service
{
public static class SafeMailHelper
{
public static async Task Run(Func<Task> func, [CallerMemberName] string caller = "")
{
try
{
await func();
}
catch (Exception ex)
{
Log.Logger.Error($"【邮件失败 - {caller}】: {ex.Message}");
}
}
public static async Task<T?> Run<T>(Func<Task<T>> func, [CallerMemberName] string caller = "")
{
try
{
return await func();
}
catch (Exception ex)
{
Log.Logger.Error($"【邮件失败 - {caller}】: {ex.Message}");
}
return default;
}
}
public interface IMailVerificationService
{
Task AnolymousSendEmail(Guid trialId, string emailAddress, int verificationCode);
Task SendEmailVerification(string emailAddress, int verificationCode);
Task SenMFAVerifyEmail(Guid userId, string userName, string emailAddress, int verificationCode, UserMFAType mfaType = UserMFAType.Login);
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", string baseUrl = "");
Task SiteSurveyUserJoinEmail(Guid trialId, Guid userId, string userTypes, string baseUrl, string rootUrl);
Task ExternalUserJoinEmail(Guid trialId, Guid userId, string userTypes, string baseUrl, string rootUrl);
Task<(Guid identityUserId, Guid userRoleId)> DoctorJoinTrialEmail(Guid trialId, Guid doctorId, string baseUrl, string rootUrl);
Task UserFeedBackMail(Guid feedBackId);
Task AfterUserModifyPasswordSendEmailAsync(Guid userId);
Task SiteSuervyCheckUser(Guid trialId, string email, string name);
Task SiteSuervyUpdateUser(Guid trialSiteId, string email, string name, string url);
}
[ApiExplorerSettings(GroupName = "Common")]
public class MailVerificationService(IRepository<VerificationCode> _verificationCodeRepository,
IRepository<SystemBasicData> _systemBasicDatarepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<TrialSite> _trialSiteRepository,
IRepository<UserRole> _userRoleRepository,
IRepository<UserLog> _userLogRepository,
IRepository<IdentityUser> _identityUserRepository,
IRepository<UserFeedBack> _userFeedBackRepository,
ITokenService _tokenService,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<Trial> _trialRepository,
IRepository<UserType> _userTypeRepository,
IRepository<Doctor> _doctorTypeRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig,
IDistributedLockProvider _distributedLockProvider, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IMailVerificationService
{
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
/// <summary>
/// 获取邮件主题和html 通用封装 以用户语言为主没有的就用当前的请求语言_userInfo.IsEn_Us
/// </summary>
/// <param name="scenario"></param>
/// <param name="messageToSend"></param>
/// <param name="emailFunc"></param>
/// <param name="userWorkLanguage"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
private async Task<EmailNoticeConfig> GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario scenario, MimeMessage messageToSend,
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailFunc, UserWorkLanguage? userWorkLanguage = null)
{
var configInfo = await _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario).FirstOrDefaultAsync();
if (configInfo == null)
{
Log.Logger.Error($"系统未找到当前场景:{scenario}邮件配置信息");
throw new BusinessValidationFailedException("系统未找到当前场景邮件配置信息,请联系运维人员核查");
}
bool isEn_Us = userWorkLanguage.HasValue ? userWorkLanguage.Value == UserWorkLanguage.US : _userInfo.IsEn_Us;
var (topicStr, htmlBodyStr) = isEn_Us ? (configInfo.EmailTopic, configInfo.EmailHtmlContent) : (configInfo.EmailTopicCN, configInfo.EmailHtmlContentCN);
try
{
//每个场景修改主题 和body的逻辑不一样
(topicStr, htmlBodyStr) = emailFunc((topicStr, htmlBodyStr));
}
catch (Exception ex)
{
Log.Logger.Error($"邮件模板内容有误,填充内容出现问题,需要核查{scenario}场景邮件配置信息");
throw new BusinessValidationFailedException("邮件模板内容有误,填充内容出现问题,请联系运维人员核查");
}
messageToSend.Subject = topicStr;
var builder = new BodyBuilder();
builder.HtmlBody = htmlBodyStr;
messageToSend.Body = builder.ToMessageBody();
return configInfo;
}
public async Task<EmailNoticeConfig> GetEmailConfigInfoAsync(EmailBusinessScenario scenario)
{
var configInfo = await _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario).Include(t => t.EmailNoticeUserTypeList).FirstOrDefaultAsync();
if (configInfo == null)
{
Log.Logger.Error($"系统未找到当前场景:{scenario}邮件配置信息");
throw new BusinessValidationFailedException("系统未找到当前场景邮件配置信息,请联系运维人员核查");
}
return configInfo;
}
private EventHandler<MessageSentEventArgs> GetEmailSuccessHandle(Guid userId, int verificationCode, string email = "")
{
EventHandler<MessageSentEventArgs> sucessHandle = (sender, args) =>
{
// args.Response
var code = verificationCode.ToString();
_ = _verificationCodeRepository.AddAsync(new VerificationCode()
{
CodeType = VerifyType.Email,
HasSend = true,
Code = code,
UserId = userId,
EmailOrPhone = email,
ExpirationTime = DateTime.Now.AddMinutes(3)
}).Result;
_ = _verificationCodeRepository.SaveChangesAsync().Result;
};
return sucessHandle;
}
private string ReplaceCompanyName(string needDealtxt)
{
var str = needDealtxt.Replace("{company}", _userInfo.IsEn_Us ? _systemEmailConfig.CompanyName : _systemEmailConfig.CompanyNameCN)
.Replace("{company abbreviation}", _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN);
return str;
}
private string ReplacePlatformName(string needDealtxt)
{
var platformName = _userInfo.IsEn_Us ? _systemEmailConfig.PlatformName : _systemEmailConfig.PlatformNameCN;
var str = needDealtxt.Replace("{platformName}", platformName);
return str;
}
//MFA
public async Task SenMFAVerifyEmail(Guid userId, string userName, string emailAddress, int verificationCode, UserMFAType mfaType = UserMFAType.Login)
{
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
//收件地址
messageToSend.To.Add(new MailboxAddress(userName, emailAddress));
//主题---[来自{0}] 关于MFA邮箱验证的提醒
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
userName,
verificationCode
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(mfaType == UserMFAType.Login ? EmailBusinessScenario.MFALogin : EmailBusinessScenario.MFAUnlock, messageToSend, emailConfigFunc);
var sucessHandle = GetEmailSuccessHandle(userId, verificationCode, emailAddress);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, sucessHandle);
}
/// <summary>
/// Reviewer简历录入 发送验证码
/// </summary>
/// <param name="emailAddress"></param>
/// <param name="verificationCode"></param>
/// <returns></returns>
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));
//主题
//---[来自展影IRC]的提醒
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
"Sir/Madam",
//---您正在参与展影医疗IRC项目
companyName,
verificationCode
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.ReviewerLogin, messageToSend, emailConfigFunc);
//此时不知道用户
var sucessHandle = GetEmailSuccessHandle(Guid.Empty, verificationCode, emailAddress);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, sucessHandle);
}
//中心调研 登陆 发送验证码
public async Task AnolymousSendEmail(Guid trialId, string emailAddress, int verificationCode)
{
//throw new BusinessValidationFailedException("模拟邮件取数据或者发送异常!!!");
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(String.Empty, emailAddress));
//主题
//$"[来自展影IRC] [{researchProgramNo}] 关于中心调研的提醒";
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
"Sir/Madam",
//---您正在参与展影医疗IRC项目中心调研工作
companyName,
verificationCode
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SiteSurveyLogin, messageToSend, emailConfigFunc);
//此时不知道用户
var sucessHandle = GetEmailSuccessHandle(Guid.Empty, verificationCode, emailAddress);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo, sucessHandle);
}
#region 邮件已修改
//添加用户发送邮件
public async Task AddUserSendEmailAsync(Guid userId, string baseUrl, string routeUrl)
{
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).Include(t => t.UserRoleList).ThenInclude(c => c.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));
//主题
//---[来自展影IRC] 关于创建账户的提醒
var token = _tokenService.GetToken(new UserTokenInfo() { IdentityUserId = sysUserInfo.Id });
await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new IdentityUser() { EmailToken = token });
routeUrl = routeUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&UserName=" + sysUserInfo.UserName + "&lang=" + (_userInfo.IsEn_Us ? "en" : "zh") + "&access_token=" + token;
var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));
var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";
var companyName = sysUserInfo.UserWorkLanguage == UserWorkLanguage.US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
sysUserInfo.FullName,
sysUserInfo.EMail,
//string.Join(',', sysUserInfo.UserRoleList.Select(t => t.UserTypeRole.UserTypeShortName)),
redirectUrl
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SysCreateUser, messageToSend, emailConfigFunc, sysUserInfo.UserWorkLanguage);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
}
//管理员重置密码发送邮件
public async Task AdminResetPwdSendEmailAsync(Guid userId, string pwdNotMd5 = "123456", string baseUrl = "")
{
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).Include(t => t.UserRoleList).ThenInclude(c => c.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));
//主题
//---[来自展影IRC] 关于重置账户密码的提醒
var companyName = sysUserInfo.UserWorkLanguage == UserWorkLanguage.US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
sysUserInfo.FullName,
sysUserInfo.UserName,
//string.Join(',', sysUserInfo.UserRoleList.Select(t => t.UserTypeRole.UserTypeShortName)),
pwdNotMd5,
baseUrl
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SysResetPassword, messageToSend, emailConfigFunc, sysUserInfo.UserWorkLanguage);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
}
//用户重置邮箱
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));
//主题
//---[来自展影IRC] 关于重置邮箱的提醒
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
userName,
//---您正在进行邮箱重置操作
verificationCode
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.UserResetEmail, messageToSend, emailConfigFunc);
var sucessHandle = GetEmailSuccessHandle(userId, verificationCode, emailAddress);
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));
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
"Sir/Madam",
//---您正在进行邮箱重置密码操作
verificationCode
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.UnloginUseEmailResetPassword, messageToSend, emailConfigFunc);
////此时不知道用户
var sucessHandle = GetEmailSuccessHandle(Guid.Empty, verificationCode, emailAddress);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, sucessHandle);
}
//外部用户 加入项目
public async Task ExternalUserJoinEmail(Guid trialId, Guid userId, string userTypes, string baseUrl, string rootUrl)
{
var trialInfo = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId)).IfNullThrowException();
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).FirstOrDefaultAsync()).IfNullThrowException();
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
//收件地址
messageToSend.To.Add(new MailboxAddress(String.Empty, sysUserInfo.EMail));
//主题
// $"[来自展影IRC] [{trialInfo.ResearchProgramNo}]邀请信";
var token = _tokenService.GetToken(new UserTokenInfo() { IdentityUserId = sysUserInfo.Id });
if (sysUserInfo.IsFirstAdd)
{
await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new Domain.Models.IdentityUser() { EmailToken = token });
}
var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));
var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&lang=" + (_userInfo.IsEn_Us ? "en" : "zh") + "&access_token=" + token;
var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
sysUserInfo.FullName,
trialInfo.ExperimentName,
trialInfo.ResearchProgramNo,
trialInfo.TrialCode,
sysUserInfo.IsFirstAdd ? sysUserInfo.EMail : sysUserInfo.UserName,
userTypes,
sysUserInfo.IsFirstAdd ? redirectUrl : baseUrl
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(sysUserInfo.IsFirstAdd ? EmailBusinessScenario.SiteUseOrExternalUserFirstrJoinTrial : EmailBusinessScenario.SiteUserOrExternalUserExistJoinTrial, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo, null);
}
//Site调研 用户加入项目
public async Task SiteSurveyUserJoinEmail(Guid trialId, Guid userId, string userTypes, string baseUrl, string rootUrl)
{
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).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));
//主题
// $"[来自展影IRC] [{trialInfo.ResearchProgramNo}]邀请信";
var token = _tokenService.GetToken(new UserTokenInfo() { IdentityUserId = sysUserInfo.Id });
if (sysUserInfo.IsFirstAdd)
{
await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new Domain.Models.IdentityUser() { EmailToken = token });
}
var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&lang=" + (_userInfo.IsEn_Us ? "en" : "zh") + "&access_token=" + token;
var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));
var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
sysUserInfo.FullName,
trialInfo.ExperimentName,
trialInfo.ResearchProgramNo,
trialInfo.TrialCode,
sysUserInfo.IsFirstAdd ? sysUserInfo.EMail : sysUserInfo.UserName,
userTypes,
sysUserInfo.IsFirstAdd ? redirectUrl : baseUrl
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(sysUserInfo.IsFirstAdd ? EmailBusinessScenario.SiteUseOrExternalUserFirstrJoinTrial : EmailBusinessScenario.SiteUserOrExternalUserExistJoinTrial, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
}
#endregion
//医生生成账号加入 或者已存在账号加入到项目中
public async Task<(Guid identityUserId, Guid userRoleId)> DoctorJoinTrialEmail(Guid trialId, Guid doctorId, string baseUrl, string rootUrl)
{
var doctor = await _doctorTypeRepository.FindAsync(doctorId);
var sysUserInfo = new IdentityUser();
var userType = await _userTypeRepository.FirstAsync(t => t.UserTypeEnum == UserTypeEnum.IndependentReviewer);
//需要创建新的账户
var isNeedCreateNewUser = false;
var @lock = _distributedLockProvider.CreateLock($"UserCode");
using (await @lock.AcquireAsync())
{
var isDoctorHaveAccount = await _userRoleRepository.AnyAsync(t => t.DoctorId == doctorId || t.IdentityUser.EMail == doctor.EMail);
if (!isDoctorHaveAccount)
{
isNeedCreateNewUser = true;
var saveItem = new IdentityUser() { 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;
}
//通过医生信息,设置工作语言
var nation = _doctorTypeRepository.Where(t => t.Id == doctorId).Select(t => t.Nation).FirstOrDefault();
saveItem.UserWorkLanguage = nation == DoctorNation.CN ? UserWorkLanguage.CN : UserWorkLanguage.US;
saveItem.UserCeateSource = UserCeateSource.ReviewerSelect;
saveItem.TrialId = trialId;
saveItem.Code = _identityUserRepository.Select(t => t.Code).DefaultIfEmpty().Max() + 1;
saveItem.UserCode = AppSettings.GetCodeStr(saveItem.Code, nameof(IdentityUser));
saveItem.UserRoleList = new List<UserRole>() { new UserRole() { DoctorId = doctorId, UserTypeEnum = UserTypeEnum.IndependentReviewer, UserTypeId = userType.Id } };
var savedUser = await _identityUserRepository.AddAsync(saveItem);
//下面获取Token 需要这部分信息
sysUserInfo = savedUser;
}
else
{
sysUserInfo = (await _identityUserRepository.Where(t => t.UserRoleList.Any(t => t.DoctorId == doctorId || t.IdentityUser.EMail == doctor.EMail), true).Include(t => t.UserRoleList).FirstOrDefaultAsync()).IfNullThrowException();
var findRole = sysUserInfo.UserRoleList.FirstOrDefault(t => t.UserTypeId == userType.Id);
//不存在该角色,那么就加入该角色
if (findRole == null)
{
sysUserInfo.UserRoleList.Add(new UserRole() { DoctorId = doctorId, UserTypeEnum = UserTypeEnum.IndependentReviewer, UserTypeId = userType.Id });
}
else
{
findRole.IsUserRoleDisabled = false;
}
sysUserInfo.Status = UserStateEnum.Enable;
}
//保证能有userRoleId
await _userRoleRepository.SaveChangesAsync();
}
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));
var token = _tokenService.GetToken(new UserTokenInfo() { IdentityUserId = sysUserInfo.Id });
if (sysUserInfo.IsFirstAdd)
{
await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new Domain.Models.IdentityUser() { EmailToken = token });
}
var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&lang=" + (_userInfo.IsEn_Us ? "en" : "zh") + "&access_token=" + token;
var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));
var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";
//主题
// $"[来自展影IRC] [{trialInfo.ResearchProgramNo}]邀请信";
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
sysUserInfo.FullName,
trialInfo.ExperimentName,
trialInfo.ResearchProgramNo,
trialInfo.TrialCode,
sysUserInfo.IsFirstAdd ? sysUserInfo.EMail : sysUserInfo.UserName,
userType.UserTypeName,
sysUserInfo.IsFirstAdd ? redirectUrl : baseUrl
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(sysUserInfo.IsFirstAdd ? EmailBusinessScenario.DoctorUserFirstJoinTrial : EmailBusinessScenario.DoctorUserExistJoinTrial, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo, null);
//创建账号 和创建角色 一条,更新的时候才记录更新角色
if (isNeedCreateNewUser == false)
{
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = _userInfo.IdentityUserId, ActionUserName = _userInfo.UserName, TargetIdentityUserId = sysUserInfo.Id, OptType = UserOptType.UpdateUserRole }, true);
}
return (sysUserInfo.Id, sysUserInfo.UserRoleList.First(t => t.UserTypeEnum == UserTypeEnum.IndependentReviewer).Id);
}
//用户反馈邮件
public async Task UserFeedBackMail(Guid feedBackId)
{
var feedBack = await _userFeedBackRepository.Where(t => t.Id == feedBackId).Include(t => t.CreateUserRole.UserTypeRole).Include(t => t.CreateUserRole.IdentityUser).FirstNotNullAsync();
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
var isHaveTrialId = feedBack.TrialId != null;
var trialinfo = await _trialRepository.Where(x => x.Id == feedBack.TrialId).FirstOrDefaultAsync();
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
var emialScenario = feedBack.VisitTaskId != null ? EmailBusinessScenario.IRImageError : (feedBack.SubjectVisitId != null ? EmailBusinessScenario.TrialSubjectVisitFeedBack : (feedBack.TrialId != null ? EmailBusinessScenario.TrialFeedBack : EmailBusinessScenario.SysFeedBack));
var emailConfigInfo = await GetEmailConfigInfoAsync(emialScenario);
var userTypeEnumList = emailConfigInfo.EmailNoticeUserTypeList.Where(t => t.EmailUserType == EmailUserType.To).Select(t => t.UserType).ToList();
var emailList = await _userRoleRepository.Where(t => userTypeEnumList.Contains(t.UserTypeEnum) && t.IsUserRoleDisabled == false && t.IdentityUser.Status == UserStateEnum.Enable &&
(isHaveTrialId ? t.IdentityUser.UserTrialList.Any(t => t.TrialId == feedBack.TrialId && t.TrialUserRoleList.Any(c => userTypeEnumList.Contains(c.UserRole.UserTypeEnum))) : true)).Select(t => new { t.IdentityUser.EMail, t.UserTypeEnum, t.IdentityUser.FullName }).ToListAsync();
foreach (var email in emailList)
{
messageToSend.To.Add(new MailboxAddress(email.FullName, email.EMail));
}
var userNames = string.Join(',', emailList.Select(t => t.FullName));
//影像阅片反馈 pm
if (feedBack.VisitTaskId != null)
{
var emailType = await _dictionaryRepository.Where(t => t.Parent.Code == "FeedBackTypeToIR" && t.ParentId != null && t.Code == ((int)feedBack.QuestionType).ToString()).Select(t => _userInfo.IsEn_Us ? t.Value : t.ValueCN).FirstOrDefaultAsync();
var info = await _visitTaskRepository.Where(t => t.Id == feedBack.VisitTaskId).Select(t => new { t.Trial.ResearchProgramNo, t.Trial.TrialCode, SubejctCode = t.Subject.Code, t.SourceSubjectVisit.VisitName }).FirstNotNullAsync();
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, info.ResearchProgramNo, info.SubejctCode, info.VisitName);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
userNames,
info.TrialCode,
info.SubejctCode,
info.VisitName,
feedBack.CreateUserRole.UserTypeRole.UserTypeShortName,
feedBack.CreateUserRole.IdentityUser.FullName,
emailType,
feedBack.QuestionDescription,
_systemEmailConfig.SiteUrl
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.IRImageError, messageToSend, emailConfigFunc);
}
else if (feedBack.SubjectVisitId != null)
{
var emailType = await _dictionaryRepository.Where(t => t.Parent.Code == "Email_BusinessScenario" && t.ParentId != null && t.Code == ((int)EmailBusinessScenario.TrialSubjectVisitFeedBack).ToString()).Select(t => _userInfo.IsEn_Us ? t.Value : t.ValueCN).FirstOrDefaultAsync();
var info = await _subjectVisitRepository.Where(t => t.Id == feedBack.SubjectVisitId).Select(t => new { t.Trial.ResearchProgramNo, t.Trial.TrialCode, SubejctCode = t.Subject.Code, t.VisitName }).FirstNotNullAsync();
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, info.ResearchProgramNo, info.SubejctCode, info.VisitName);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
userNames,
info.TrialCode,
info.SubejctCode,
info.VisitName,
feedBack.CreateUserRole.UserTypeRole.UserTypeShortName,
feedBack.CreateUserRole.IdentityUser.FullName,
emailType,
feedBack.QuestionDescription,
_systemEmailConfig.SiteUrl
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.TrialSubjectVisitFeedBack, messageToSend, emailConfigFunc);
}
//项目相关的反馈 pm admin
else if (feedBack.TrialId != null)
{
var emailType = await _dictionaryRepository.Where(t => t.Parent.Code == "Email_BusinessScenario" && t.ParentId != null && t.Code == ((int)EmailBusinessScenario.TrialFeedBack).ToString()).Select(t => _userInfo.IsEn_Us ? t.Value : t.ValueCN).FirstOrDefaultAsync();
var info = await _trialRepository.Where(t => t.Id == feedBack.TrialId).Select(t => new { t.ResearchProgramNo, t.TrialCode }).FirstNotNullAsync();
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, info.ResearchProgramNo);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
userNames,
info.TrialCode,
feedBack.CreateUserRole.UserTypeRole.UserTypeShortName,
feedBack.CreateUserRole.IdentityUser.FullName,
emailType,
feedBack.QuestionDescription,
_systemEmailConfig.SiteUrl
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.TrialFeedBack, messageToSend, emailConfigFunc);
}
//项目无关的反馈 admin
else
{
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
userNames,
feedBack.CreateUserRole.UserTypeRole.UserTypeShortName,
feedBack.CreateUserRole.IdentityUser.FullName,
feedBack.QuestionDescription,
_systemEmailConfig.SiteUrl
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SysFeedBack, messageToSend, emailConfigFunc);
}
if (trialinfo == null)
{
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
}
else
{
await SendEmailHelper.SendEmailAsync(messageToSend, trialinfo);
}
}
//用户修改密码发送邮件
public async Task AfterUserModifyPasswordSendEmailAsync(Guid userId)
{
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).FirstOrDefaultAsync()).IfNullThrowException();
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
//收件地址
messageToSend.To.Add(new MailboxAddress(sysUserInfo.FullName, sysUserInfo.EMail));
//主题
//---[来自展影IRC] 关于重置邮箱的提醒
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName);
var htmlBodyStr = string.Format(ReplacePlatformName(ReplaceCompanyName(input.htmlBodyStr)),
sysUserInfo.FullName
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.IdentityUser_ModifyPassword, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
}
//中心调研核对人员提醒
public async Task SiteSuervyCheckUser(Guid trialId, string email, string name)
{
var trialInfo = await _trialRepository.Where(t => t.Id == trialId).FirstOrDefaultAsync();
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
//收件地址
messageToSend.To.Add(new MailboxAddress(name, email));
//主题
//---[来自展影IRC] 关于重置邮箱的提醒
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
name,
trialInfo.TrialCode,
trialInfo.ResearchProgramNo
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SiteSurvey_CheckUser, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
}
public async Task SiteSuervyUpdateUser(Guid trialSiteId, string email, string name, string url)
{
var siteInfo = await _trialSiteRepository.Where(t => t.Id == trialSiteId).Include(x => x.Trial).FirstOrDefaultAsync();
var trialInfo = siteInfo.Trial;
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
//收件地址
messageToSend.To.Add(new MailboxAddress(name, email));
//主题
//---[来自展影IRC] 关于重置邮箱的提醒
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
{
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
name,
trialInfo.TrialCode,
siteInfo.TrialSiteCode,
siteInfo.TrialSiteName,
url
);
return (topicStr, htmlBodyStr);
};
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SiteSurvey_UpdateUser, messageToSend, emailConfigFunc);
await SendEmailHelper.SendEmailAsync(messageToSend, trialInfo);
}
}
}