mirror of
https://gitee.com/yudaocode/yudao-boot-mini.git
synced 2026-03-22 05:27:15 +08:00
Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
# Conflicts: # yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyWrapper.java # yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java # yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSendReqVO.java # yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImplTest.java
This commit is contained in:
@@ -21,13 +21,15 @@ public class MailSendApiImpl implements MailSendApi {
|
||||
|
||||
@Override
|
||||
public Long sendSingleMailToAdmin(MailSendSingleToUserReqDTO reqDTO) {
|
||||
return mailSendService.sendSingleMailToAdmin(reqDTO.getMail(), reqDTO.getUserId(),
|
||||
return mailSendService.sendSingleMailToAdmin(reqDTO.getUserId(),
|
||||
reqDTO.getToMails(), reqDTO.getCcMails(), reqDTO.getBccMails(),
|
||||
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long sendSingleMailToMember(MailSendSingleToUserReqDTO reqDTO) {
|
||||
return mailSendService.sendSingleMailToMember(reqDTO.getMail(), reqDTO.getUserId(),
|
||||
return mailSendService.sendSingleMailToMember(reqDTO.getUserId(),
|
||||
reqDTO.getToMails(), reqDTO.getCcMails(), reqDTO.getBccMails(),
|
||||
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ package cn.iocoder.yudao.module.system.api.mail.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -16,13 +18,24 @@ public class MailSendSingleToUserReqDTO {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* 如果非空,则加载对应用户的邮箱,添加到 {@link #toMails} 中
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
* 收件邮箱
|
||||
*/
|
||||
@Email
|
||||
private String mail;
|
||||
private List<@Email String> toMails;
|
||||
/**
|
||||
* 抄送邮箱
|
||||
*/
|
||||
private List<@Email String> ccMails;
|
||||
/**
|
||||
* 密送邮箱
|
||||
*/
|
||||
private List<@Email String> bccMails;
|
||||
|
||||
|
||||
/**
|
||||
* 邮件模板编号
|
||||
|
||||
@@ -11,6 +11,24 @@ tag: Yunai.local
|
||||
"code": "1024"
|
||||
}
|
||||
|
||||
### 请求 /login 接口【加密 AES】 => 成功
|
||||
POST {{baseUrl}}/system/auth/login
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenantId}}
|
||||
tag: Yunai.local
|
||||
X-API-ENCRYPT: true
|
||||
|
||||
WvSX9MOrenyGfBhEM0g1/hHgq8ocktMZ9OwAJ6MOG5FUrzYF/rG5JF1eMptQM1wT73VgDS05l/37WeRtad+JrqChAul/sR/SdOsUKqjBhvvQx1JVhzxr6s8uUP67aKTSZ6Psv7O32ELxXrzSaQvG5CInzz3w6sLtbNNLd1kXe6Q=
|
||||
|
||||
### 请求 /login 接口【加密 RSA】 => 成功
|
||||
POST {{baseUrl}}/system/auth/login
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenantId}}
|
||||
tag: Yunai.local
|
||||
X-API-ENCRYPT: true
|
||||
|
||||
e7QZTork9ZV5CmgZvSd+cHZk3xdUxKtowLM02kOha+gxHK2H/daU8nVBYS3+bwuDRy5abf+Pz1QJJGVAEd27wwrXBmupOOA/bhpuzzDwcRuJRD+z+YgiNoEXFDRHERxPYlPqAe9zAHtihD0ceub1AjybQsEsROew4C3Q602XYW0=
|
||||
|
||||
### 请求 /login 接口 => 成功(无验证码)
|
||||
POST {{baseUrl}}/system/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
@@ -56,6 +56,15 @@ public class DeptController {
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除部门")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:dept:delete')")
|
||||
public CommonResult<Boolean> deleteDeptList(@RequestParam("ids") List<Long> ids) {
|
||||
deptService.deleteDeptList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获取部门列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:dept:query')")
|
||||
|
||||
@@ -91,7 +91,8 @@ public class MailTemplateController {
|
||||
@Operation(summary = "发送短信")
|
||||
@PreAuthorize("@ss.hasPermission('system:mail-template:send-mail')")
|
||||
public CommonResult<Long> sendMail(@Valid @RequestBody MailTemplateSendReqVO sendReqVO) {
|
||||
return success(mailSendService.sendSingleMailToAdmin(sendReqVO.getMail(), getLoginUserId(),
|
||||
return success(mailSendService.sendSingleMailToAdmin(getLoginUserId(),
|
||||
sendReqVO.getToMails(), sendReqVO.getCcMails(), sendReqVO.getBccMails(),
|
||||
sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,11 @@ package cn.iocoder.yudao.module.system.controller.admin.mail.vo.log;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 邮件日志 Response VO")
|
||||
@Data
|
||||
public class MailLogRespVO {
|
||||
@@ -22,8 +20,14 @@ public class MailLogRespVO {
|
||||
@Schema(description = "用户类型,参见 UserTypeEnum 枚举", example = "2")
|
||||
private Byte userType;
|
||||
|
||||
@Schema(description = "接收邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "76854@qq.com")
|
||||
private String toMail;
|
||||
@Schema(description = "接收邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user1@example.com, user2@example.com")
|
||||
private List<String> toMails;
|
||||
|
||||
@Schema(description = "抄送邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user3@example.com, user4@example.com")
|
||||
private List<String> ccMails;
|
||||
|
||||
@Schema(description = "密送邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user5@example.com, user6@example.com")
|
||||
private List<String> bccMails;
|
||||
|
||||
@Schema(description = "邮箱账号编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18107")
|
||||
private Long accountId;
|
||||
|
||||
@@ -3,17 +3,24 @@ package cn.iocoder.yudao.module.system.controller.admin.mail.vo.template;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Schema(description = "管理后台 - 邮件发送 Req VO")
|
||||
@Data
|
||||
public class MailTemplateSendReqVO {
|
||||
|
||||
@Schema(description = "接收邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "7685413@qq.com")
|
||||
@Schema(description = "接收邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "[user1@example.com, user2@example.com]")
|
||||
@NotEmpty(message = "接收邮箱不能为空")
|
||||
private String mail;
|
||||
private List<String> toMails;
|
||||
|
||||
@Schema(description = "抄送邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "[user3@example.com, user4@example.com]")
|
||||
private List<String> ccMails;
|
||||
|
||||
@Schema(description = "密送邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "[user5@example.com, user6@example.com]")
|
||||
private List<String> bccMails;
|
||||
|
||||
@Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01")
|
||||
@NotNull(message = "模板编码不能为空")
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.mail;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler;
|
||||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
||||
import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
@@ -12,6 +13,7 @@ import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -47,10 +49,22 @@ public class MailLogDO extends BaseDO implements Serializable {
|
||||
* 枚举 {@link UserTypeEnum}
|
||||
*/
|
||||
private Integer userType;
|
||||
|
||||
/**
|
||||
* 接收邮箱地址
|
||||
*/
|
||||
private String toMail;
|
||||
@TableField(typeHandler = StringListTypeHandler.class)
|
||||
private List<String> toMails;
|
||||
/**
|
||||
* 接收邮箱地址
|
||||
*/
|
||||
@TableField(typeHandler = StringListTypeHandler.class)
|
||||
private List<String> ccMails;
|
||||
/**
|
||||
* 密送邮箱地址
|
||||
*/
|
||||
@TableField(typeHandler = StringListTypeHandler.class)
|
||||
private List<String> bccMails;
|
||||
|
||||
/**
|
||||
* 邮箱账号编号
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package cn.iocoder.yudao.module.system.dal.mysql.mail;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
@@ -14,11 +16,12 @@ public interface MailLogMapper extends BaseMapperX<MailLogDO> {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<MailLogDO>()
|
||||
.eqIfPresent(MailLogDO::getUserId, reqVO.getUserId())
|
||||
.eqIfPresent(MailLogDO::getUserType, reqVO.getUserType())
|
||||
.likeIfPresent(MailLogDO::getToMail, reqVO.getToMail())
|
||||
.eqIfPresent(MailLogDO::getAccountId, reqVO.getAccountId())
|
||||
.eqIfPresent(MailLogDO::getTemplateId, reqVO.getTemplateId())
|
||||
.eqIfPresent(MailLogDO::getSendStatus, reqVO.getSendStatus())
|
||||
.betweenIfPresent(MailLogDO::getSendTime, reqVO.getSendTime())
|
||||
.apply(StrUtil.isNotBlank(reqVO.getToMail()),
|
||||
MyBatisUtils.findInSet("to_mails", reqVO.getToMail()))
|
||||
.orderByDesc(MailLogDO::getId));
|
||||
}
|
||||
|
||||
|
||||
@@ -136,15 +136,20 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||
.map(entry -> percentCode(entry.getKey()) + "=" + percentCode(String.valueOf(entry.getValue())))
|
||||
.collect(Collectors.joining("&"));
|
||||
|
||||
// 2.1 请求 Header
|
||||
// 2. 请求 Body
|
||||
String requestBody = ""; // 短信 API 为 RPC 接口,query parameters 在 uri 中拼接,因此 request body 如果没有特殊要求,设置为空
|
||||
String hashedRequestPayload = DigestUtil.sha256Hex(requestBody);
|
||||
|
||||
// 3.1 请求 Header
|
||||
TreeMap<String, String> headers = new TreeMap<>();
|
||||
headers.put("host", HOST);
|
||||
headers.put("x-acs-version", VERSION);
|
||||
headers.put("x-acs-action", apiName);
|
||||
headers.put("x-acs-date", FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone("GMT")).format(new Date()));
|
||||
headers.put("x-acs-signature-nonce", IdUtil.randomUUID());
|
||||
headers.put("x-acs-content-sha256", hashedRequestPayload);
|
||||
|
||||
// 2.2 构建签名 Header
|
||||
// 3.2 构建签名 Header
|
||||
StringBuilder canonicalHeaders = new StringBuilder(); // 构造请求头,多个规范化消息头,按照消息头名称(小写)的字符代码顺序以升序排列后拼接在一起
|
||||
StringBuilder signedHeadersBuilder = new StringBuilder(); // 已签名消息头列表,多个请求头名称(小写)按首字母升序排列并以英文分号(;)分隔
|
||||
headers.entrySet().stream().filter(entry -> entry.getKey().toLowerCase().startsWith("x-acs-")
|
||||
@@ -157,13 +162,13 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||
});
|
||||
String signedHeaders = signedHeadersBuilder.substring(0, signedHeadersBuilder.length() - 1);
|
||||
|
||||
// 3. 请求 Body
|
||||
String requestBody = ""; // 短信 API 为 RPC 接口,query parameters 在 uri 中拼接,因此 request body 如果没有特殊要求,设置为空。
|
||||
String hashedRequestBody = DigestUtil.sha256Hex(requestBody);
|
||||
|
||||
// 4. 构建 Authorization 签名
|
||||
String canonicalRequest = "POST" + "\n" + "/" + "\n" + queryString + "\n"
|
||||
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestBody;
|
||||
String canonicalRequest = "POST" + "\n" +
|
||||
"/" + "\n" +
|
||||
queryString + "\n" +
|
||||
canonicalHeaders + "\n" +
|
||||
signedHeaders + "\n" +
|
||||
hashedRequestPayload;
|
||||
String hashedCanonicalRequest = DigestUtil.sha256Hex(canonicalRequest);
|
||||
String stringToSign = "ACS3-HMAC-SHA256" + "\n" + hashedCanonicalRequest;
|
||||
String signature = SecureUtil.hmacSha256(properties.getApiSecret()).digestHex(stringToSign); // 计算签名
|
||||
@@ -184,7 +189,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||
@SneakyThrows
|
||||
private static String percentCode(String str) {
|
||||
Assert.notNull(str, "str 不能为空");
|
||||
return HttpUtils.encodeUtf8(str)
|
||||
return URLEncoder.encode(str, StandardCharsets.UTF_8.name())
|
||||
.replace("+", "%20") // 加号 "+" 被替换为 "%20"
|
||||
.replace("*", "%2A") // 星号 "*" 被替换为 "%2A"
|
||||
.replace("%7E", "~"); // 波浪号 "%7E" 被替换为 "~"
|
||||
|
||||
@@ -5,6 +5,9 @@ import lombok.Data;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 邮箱发送消息
|
||||
*
|
||||
@@ -21,8 +24,16 @@ public class MailSendMessage {
|
||||
/**
|
||||
* 接收邮件地址
|
||||
*/
|
||||
@NotNull(message = "接收邮件地址不能为空")
|
||||
private String mail;
|
||||
@NotEmpty(message = "接收邮件地址不能为空")
|
||||
private Collection<String> toMails;
|
||||
/**
|
||||
* 抄送邮件地址
|
||||
*/
|
||||
private Collection<String> ccMails;
|
||||
/**
|
||||
* 密送邮件地址
|
||||
*/
|
||||
private Collection<String> bccMails;
|
||||
/**
|
||||
* 邮件账号编号
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,11 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
/**
|
||||
* Mail 邮件相关消息的 Producer
|
||||
*
|
||||
@@ -24,17 +29,22 @@ public class MailProducer {
|
||||
* 发送 {@link MailSendMessage} 消息
|
||||
*
|
||||
* @param sendLogId 发送日志编码
|
||||
* @param mail 接收邮件地址
|
||||
* @param toMails 接收邮件地址
|
||||
* @param ccMails 抄送邮件地址
|
||||
* @param bccMails 密送邮件地址
|
||||
* @param accountId 邮件账号编号
|
||||
* @param nickname 邮件发件人
|
||||
* @param title 邮件标题
|
||||
* @param content 邮件内容
|
||||
* @param nickname 邮件发件人
|
||||
* @param title 邮件标题
|
||||
* @param content 邮件内容
|
||||
*/
|
||||
public void sendMailSendMessage(Long sendLogId, String mail, Long accountId,
|
||||
String nickname, String title, String content) {
|
||||
public void sendMailSendMessage(Long sendLogId,
|
||||
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
Long accountId, String nickname, String title, String content) {
|
||||
MailSendMessage message = new MailSendMessage()
|
||||
.setLogId(sendLogId).setMail(mail).setAccountId(accountId)
|
||||
.setNickname(nickname).setTitle(title).setContent(content);
|
||||
.setLogId(sendLogId)
|
||||
.setToMails(toMails).setCcMails(ccMails).setBccMails(bccMails)
|
||||
.setAccountId(accountId).setNickname(nickname)
|
||||
.setTitle(title).setContent(content);
|
||||
applicationContext.publishEvent(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,13 @@ public interface DeptService {
|
||||
*/
|
||||
void deleteDept(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除部门
|
||||
*
|
||||
* @param ids 部门编号数组
|
||||
*/
|
||||
void deleteDeptList(List<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得部门信息
|
||||
*
|
||||
|
||||
@@ -88,6 +88,21 @@ public class DeptServiceImpl implements DeptService {
|
||||
deptMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST,
|
||||
allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存
|
||||
public void deleteDeptList(List<Long> ids) {
|
||||
// 校验是否有子部门
|
||||
for (Long id : ids) {
|
||||
if (deptMapper.selectCountByParentId(id) > 0) {
|
||||
throw exception(DEPT_EXITS_CHILDREN);
|
||||
}
|
||||
}
|
||||
|
||||
// 批量删除部门
|
||||
deptMapper.deleteByIds(ids);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void validateDeptExists(Long id) {
|
||||
if (id == null) {
|
||||
|
||||
@@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -35,18 +37,21 @@ public interface MailLogService {
|
||||
/**
|
||||
* 创建邮件日志
|
||||
*
|
||||
* @param userId 用户编码
|
||||
* @param userType 用户类型
|
||||
* @param toMail 收件人邮件
|
||||
* @param account 邮件账号信息
|
||||
* @param template 模版信息
|
||||
* @param userId 用户编码
|
||||
* @param userType 用户类型
|
||||
* @param toMails 收件人邮件
|
||||
* @param ccMails 收件人邮件
|
||||
* @param bccMails 收件人邮件
|
||||
* @param account 邮件账号信息
|
||||
* @param template 模版信息
|
||||
* @param templateContent 模版内容
|
||||
* @param templateParams 模版参数
|
||||
* @param isSend 是否发送成功
|
||||
* @param templateParams 模版参数
|
||||
* @param isSend 是否发送成功
|
||||
* @return 日志编号
|
||||
*/
|
||||
Long createMailLog(Long userId, Integer userType, String toMail,
|
||||
MailAccountDO account, MailTemplateDO template ,
|
||||
Long createMailLog(Long userId, Integer userType,
|
||||
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
MailAccountDO account, MailTemplateDO template,
|
||||
String templateContent, Map<String, Object> templateParams, Boolean isSend);
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.system.service.mail;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
|
||||
@@ -12,8 +13,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage;
|
||||
|
||||
@@ -41,7 +41,8 @@ public class MailLogServiceImpl implements MailLogService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long createMailLog(Long userId, Integer userType, String toMail,
|
||||
public Long createMailLog(Long userId, Integer userType,
|
||||
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
MailAccountDO account, MailTemplateDO template,
|
||||
String templateContent, Map<String, Object> templateParams, Boolean isSend) {
|
||||
MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder();
|
||||
@@ -49,7 +50,8 @@ public class MailLogServiceImpl implements MailLogService {
|
||||
logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus()
|
||||
: MailSendStatusEnum.IGNORE.getStatus())
|
||||
// 用户信息
|
||||
.userId(userId).userType(userType).toMail(toMail)
|
||||
.userId(userId).userType(userType)
|
||||
.toMails(ListUtil.toList(toMails)).ccMails(ListUtil.toList(ccMails)).bccMails(ListUtil.toList(bccMails))
|
||||
.accountId(account.getId()).fromMail(account.getMail())
|
||||
// 模板相关字段
|
||||
.templateId(template.getId()).templateCode(template.getCode()).templateNickname(template.getNickname())
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package cn.iocoder.yudao.module.system.service.mail;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -15,38 +17,53 @@ public interface MailSendService {
|
||||
/**
|
||||
* 发送单条邮件给管理后台的用户
|
||||
*
|
||||
* @param mail 邮箱
|
||||
* @param userId 用户编码
|
||||
* @param toMails 收件邮箱
|
||||
* @param ccMails 抄送邮箱
|
||||
* @param bccMails 密送邮箱
|
||||
* @param templateCode 邮件模版编码
|
||||
* @param templateParams 邮件模版参数
|
||||
* @return 发送日志编号
|
||||
*/
|
||||
Long sendSingleMailToAdmin(String mail, Long userId,
|
||||
String templateCode, Map<String, Object> templateParams);
|
||||
default Long sendSingleMailToAdmin(Long userId,
|
||||
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
String templateCode, Map<String, Object> templateParams) {
|
||||
return sendSingleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.ADMIN.getValue(),
|
||||
templateCode, templateParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送单条邮件给用户 APP 的用户
|
||||
*
|
||||
* @param mail 邮箱
|
||||
* @param userId 用户编码
|
||||
* @param toMails 收件邮箱
|
||||
* @param ccMails 抄送邮箱
|
||||
* @param bccMails 密送邮箱
|
||||
* @param templateCode 邮件模版编码
|
||||
* @param templateParams 邮件模版参数
|
||||
* @return 发送日志编号
|
||||
*/
|
||||
Long sendSingleMailToMember(String mail, Long userId,
|
||||
String templateCode, Map<String, Object> templateParams);
|
||||
default Long sendSingleMailToMember(Long userId,
|
||||
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
String templateCode, Map<String, Object> templateParams) {
|
||||
return sendSingleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.MEMBER.getValue(),
|
||||
templateCode, templateParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送单条邮件给用户
|
||||
* 发送单条邮件
|
||||
*
|
||||
* @param mail 邮箱
|
||||
* @param userId 用户编码
|
||||
* @param toMails 收件邮箱
|
||||
* @param ccMails 抄送邮箱
|
||||
* @param bccMails 密送邮箱
|
||||
* @param userId 用户编号
|
||||
* @param userType 用户类型
|
||||
* @param templateCode 邮件模版编码
|
||||
* @param templateParams 邮件模版参数
|
||||
* @return 发送日志编号
|
||||
*/
|
||||
Long sendSingleMail(String mail, Long userId, Integer userType,
|
||||
Long sendSingleMail(Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams);
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package cn.iocoder.yudao.module.system.service.mail;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.mail.MailAccount;
|
||||
import cn.hutool.extra.mail.MailUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
|
||||
@@ -13,11 +13,15 @@ import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer;
|
||||
import cn.iocoder.yudao.module.system.service.member.MemberService;
|
||||
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.hutool.extra.mail.MailAccount;
|
||||
import org.dromara.hutool.extra.mail.MailUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
@@ -50,56 +54,67 @@ public class MailSendServiceImpl implements MailSendService {
|
||||
private MailProducer mailProducer;
|
||||
|
||||
@Override
|
||||
public Long sendSingleMailToAdmin(String mail, Long userId,
|
||||
String templateCode, Map<String, Object> templateParams) {
|
||||
// 如果 mail 为空,则加载用户编号对应的邮箱
|
||||
if (StrUtil.isEmpty(mail)) {
|
||||
AdminUserDO user = adminUserService.getUser(userId);
|
||||
if (user != null) {
|
||||
mail = user.getEmail();
|
||||
}
|
||||
}
|
||||
// 执行发送
|
||||
return sendSingleMail(mail, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long sendSingleMailToMember(String mail, Long userId,
|
||||
String templateCode, Map<String, Object> templateParams) {
|
||||
// 如果 mail 为空,则加载用户编号对应的邮箱
|
||||
if (StrUtil.isEmpty(mail)) {
|
||||
mail = memberService.getMemberUserEmail(userId);
|
||||
}
|
||||
// 执行发送
|
||||
return sendSingleMail(mail, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long sendSingleMail(String mail, Long userId, Integer userType,
|
||||
public Long sendSingleMail(Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams) {
|
||||
// 校验邮箱模版是否合法
|
||||
// 1.1 校验邮箱模版是否合法
|
||||
MailTemplateDO template = validateMailTemplate(templateCode);
|
||||
// 校验邮箱账号是否合法
|
||||
// 1.2 校验邮箱账号是否合法
|
||||
MailAccountDO account = validateMailAccount(template.getAccountId());
|
||||
|
||||
// 校验邮箱是否存在
|
||||
mail = validateMail(mail);
|
||||
// 1.3 校验邮件参数是否缺失
|
||||
validateTemplateParams(template, templateParams);
|
||||
|
||||
// 2. 组装邮箱
|
||||
String userMail = getUserMail(userId, userType);
|
||||
Collection<String> toMailSet = new LinkedHashSet<>();
|
||||
Collection<String> ccMailSet = new LinkedHashSet<>();
|
||||
Collection<String> bccMailSet = new LinkedHashSet<>();
|
||||
if (Validator.isEmail(userMail)) {
|
||||
toMailSet.add(userMail);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(toMails)) {
|
||||
toMails.stream().filter(Validator::isEmail).forEach(toMailSet::add);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(ccMails)) {
|
||||
ccMails.stream().filter(Validator::isEmail).forEach(ccMailSet::add);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(bccMails)) {
|
||||
bccMails.stream().filter(Validator::isEmail).forEach(bccMailSet::add);
|
||||
}
|
||||
if (CollUtil.isEmpty(toMailSet)) {
|
||||
throw exception(MAIL_SEND_MAIL_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus());
|
||||
String title = mailTemplateService.formatMailTemplateContent(template.getTitle(), templateParams);
|
||||
String content = mailTemplateService.formatMailTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = mailLogService.createMailLog(userId, userType, mail,
|
||||
Long sendLogId = mailLogService.createMailLog(userId, userType, toMailSet, ccMailSet, bccMailSet,
|
||||
account, template, content, templateParams, isSend);
|
||||
// 发送 MQ 消息,异步执行发送短信
|
||||
if (isSend) {
|
||||
mailProducer.sendMailSendMessage(sendLogId, mail, account.getId(),
|
||||
template.getNickname(), title, content);
|
||||
mailProducer.sendMailSendMessage(sendLogId, toMailSet, ccMailSet, bccMailSet,
|
||||
account.getId(), template.getNickname(), title, content);
|
||||
}
|
||||
return sendLogId;
|
||||
}
|
||||
|
||||
private String getUserMail(Long userId, Integer userType) {
|
||||
if (userId == null || userType == null) {
|
||||
return null;
|
||||
}
|
||||
if (UserTypeEnum.ADMIN.getValue().equals(userType)) {
|
||||
AdminUserDO user = adminUserService.getUser(userId);
|
||||
if (user != null) {
|
||||
return user.getEmail();
|
||||
}
|
||||
}
|
||||
if (UserTypeEnum.MEMBER.getValue().equals(userType)) {
|
||||
return memberService.getMemberUserEmail(userId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSendMail(MailSendMessage message) {
|
||||
// 1. 创建发送账号
|
||||
@@ -107,7 +122,7 @@ public class MailSendServiceImpl implements MailSendService {
|
||||
MailAccount mailAccount = buildMailAccount(account, message.getNickname());
|
||||
// 2. 发送邮件
|
||||
try {
|
||||
String messageId = MailUtil.send(mailAccount, message.getMail(),
|
||||
String messageId = MailUtil.send(mailAccount, message.getToMails(), message.getCcMails(), message.getBccMails(),
|
||||
message.getTitle(), message.getContent(), true);
|
||||
// 3. 更新结果(成功)
|
||||
mailLogService.updateMailSendResult(message.getLogId(), messageId, null);
|
||||
@@ -120,7 +135,7 @@ public class MailSendServiceImpl implements MailSendService {
|
||||
private MailAccount buildMailAccount(MailAccountDO account, String nickname) {
|
||||
String from = StrUtil.isNotEmpty(nickname) ? nickname + " <" + account.getMail() + ">" : account.getMail();
|
||||
return new MailAccount().setFrom(from).setAuth(true)
|
||||
.setUser(account.getUsername()).setPass(account.getPassword())
|
||||
.setUser(account.getUsername()).setPass(account.getPassword().toCharArray())
|
||||
.setHost(account.getHost()).setPort(account.getPort())
|
||||
.setSslEnable(account.getSslEnable()).setStarttlsEnable(account.getStarttlsEnable());
|
||||
}
|
||||
@@ -147,16 +162,8 @@ public class MailSendServiceImpl implements MailSendService {
|
||||
return account;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String validateMail(String mail) {
|
||||
if (StrUtil.isEmpty(mail)) {
|
||||
throw exception(MAIL_SEND_MAIL_NOT_EXISTS);
|
||||
}
|
||||
return mail;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验邮件参数是否确实
|
||||
* 校验邮件参数是否缺失
|
||||
*
|
||||
* @param template 邮箱模板
|
||||
* @param templateParams 参数列表
|
||||
|
||||
@@ -255,9 +255,6 @@ public class MenuServiceImpl implements MenuService {
|
||||
return;
|
||||
}
|
||||
// 如果 id 为空,说明不用比较是否为相同 id 的菜单
|
||||
if (id == null) {
|
||||
throw exception(MENU_NAME_DUPLICATE);
|
||||
}
|
||||
if (!menu.getId().equals(id)) {
|
||||
throw exception(MENU_NAME_DUPLICATE);
|
||||
}
|
||||
|
||||
@@ -105,12 +105,40 @@ public class DeptServiceImplTest extends BaseDbUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateDeptExists_notFound() {
|
||||
public void testDeleteDeptList_success() {
|
||||
// mock 数据
|
||||
DeptDO deptDO1 = randomPojo(DeptDO.class);
|
||||
deptMapper.insert(deptDO1);
|
||||
DeptDO deptDO2 = randomPojo(DeptDO.class);
|
||||
deptMapper.insert(deptDO2);
|
||||
// 准备参数
|
||||
Long id = randomLongId();
|
||||
List<Long> ids = Arrays.asList(deptDO1.getId(), deptDO2.getId());
|
||||
|
||||
// 调用
|
||||
deptService.deleteDeptList(ids);
|
||||
// 校验数据不存在了
|
||||
assertNull(deptMapper.selectById(deptDO1.getId()));
|
||||
assertNull(deptMapper.selectById(deptDO2.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteDeptList_exitsChildren() {
|
||||
// mock 数据
|
||||
DeptDO parentDept = randomPojo(DeptDO.class);
|
||||
deptMapper.insert(parentDept);
|
||||
DeptDO childrenDeptDO = randomPojo(DeptDO.class, o -> {
|
||||
o.setParentId(parentDept.getId());
|
||||
o.setStatus(randomCommonStatus());
|
||||
});
|
||||
deptMapper.insert(childrenDeptDO);
|
||||
DeptDO anotherDept = randomPojo(DeptDO.class);
|
||||
deptMapper.insert(anotherDept);
|
||||
|
||||
// 准备参数(包含有子部门的 parentDept)
|
||||
List<Long> ids = Arrays.asList(parentDept.getId(), anotherDept.getId());
|
||||
|
||||
// 调用, 并断言异常
|
||||
assertServiceException(() -> deptService.validateDeptExists(id), DEPT_NOT_FOUND);
|
||||
assertServiceException(() -> deptService.deleteDeptList(ids), DEPT_EXITS_CHILDREN);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -10,10 +10,12 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.mail.MailLogMapper;
|
||||
import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum;
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
@@ -43,7 +45,9 @@ public class MailLogServiceImplTest extends BaseDbUnitTest {
|
||||
// 准备参数
|
||||
Long userId = randomLongId();
|
||||
Integer userType = randomEle(UserTypeEnum.values()).getValue();
|
||||
String toMail = randomEmail();
|
||||
Collection<String> toMails = Lists.newArrayList(randomEmail(), randomEmail());
|
||||
Collection<String> ccMails = Lists.newArrayList(randomEmail());
|
||||
Collection<String> bccMails = Lists.newArrayList(randomEmail());
|
||||
MailAccountDO account = randomPojo(MailAccountDO.class);
|
||||
MailTemplateDO template = randomPojo(MailTemplateDO.class);
|
||||
String templateContent = randomString();
|
||||
@@ -52,14 +56,20 @@ public class MailLogServiceImplTest extends BaseDbUnitTest {
|
||||
// mock 方法
|
||||
|
||||
// 调用
|
||||
Long logId = mailLogService.createMailLog(userId, userType, toMail, account, template, templateContent, templateParams, isSend);
|
||||
Long logId = mailLogService.createMailLog(userId, userType, toMails, ccMails, bccMails,
|
||||
account, template, templateContent, templateParams, isSend);
|
||||
// 断言
|
||||
MailLogDO log = mailLogMapper.selectById(logId);
|
||||
assertNotNull(log);
|
||||
assertEquals(MailSendStatusEnum.INIT.getStatus(), log.getSendStatus());
|
||||
assertEquals(userId, log.getUserId());
|
||||
assertEquals(userType, log.getUserType());
|
||||
assertEquals(toMail, log.getToMail());
|
||||
assertEquals(toMails.size(), log.getToMails().size());
|
||||
assertTrue(log.getToMails().containsAll(toMails));
|
||||
assertEquals(ccMails.size(), log.getCcMails().size());
|
||||
assertTrue(log.getCcMails().containsAll(ccMails));
|
||||
assertEquals(bccMails.size(), log.getBccMails().size());
|
||||
assertTrue(log.getBccMails().containsAll(bccMails));
|
||||
assertEquals(account.getId(), log.getAccountId());
|
||||
assertEquals(account.getMail(), log.getFromMail());
|
||||
assertEquals(template.getId(), log.getTemplateId());
|
||||
@@ -136,7 +146,9 @@ public class MailLogServiceImplTest extends BaseDbUnitTest {
|
||||
MailLogDO dbMailLog = randomPojo(MailLogDO.class, o -> { // 等会查询到
|
||||
o.setUserId(1L);
|
||||
o.setUserType(UserTypeEnum.ADMIN.getValue());
|
||||
o.setToMail("768@qq.com");
|
||||
o.setToMails(Lists.newArrayList("768@qq.com"));
|
||||
o.setCcMails(Lists.newArrayList());
|
||||
o.setBccMails(Lists.newArrayList());
|
||||
o.setAccountId(10L);
|
||||
o.setTemplateId(100L);
|
||||
o.setSendStatus(MailSendStatusEnum.INIT.getStatus());
|
||||
@@ -148,8 +160,8 @@ public class MailLogServiceImplTest extends BaseDbUnitTest {
|
||||
mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setUserId(2L)));
|
||||
// 测试 userType 不匹配
|
||||
mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
|
||||
// 测试 toMail 不匹配
|
||||
mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setToMail("788@.qq.com")));
|
||||
// 测试 toMails 不匹配(特殊:find_in_set 无法单测)
|
||||
// mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setToMails(Lists.newArrayList("788@qq.com"))));
|
||||
// 测试 accountId 不匹配
|
||||
mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setAccountId(11L)));
|
||||
// 测试 templateId 不匹配
|
||||
@@ -162,7 +174,7 @@ public class MailLogServiceImplTest extends BaseDbUnitTest {
|
||||
MailLogPageReqVO reqVO = new MailLogPageReqVO();
|
||||
reqVO.setUserId(1L);
|
||||
reqVO.setUserType(UserTypeEnum.ADMIN.getValue());
|
||||
reqVO.setToMail("768");
|
||||
// reqVO.setToMail("768@qq.com");
|
||||
reqVO.setAccountId(10L);
|
||||
reqVO.setTemplateId(100L);
|
||||
reqVO.setSendStatus(MailSendStatusEnum.INIT.getStatus());
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -65,14 +66,18 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendSingleMailToAdmin() {
|
||||
public void testSendSingleMail_success() {
|
||||
// 准备参数
|
||||
Long userId = randomLongId();
|
||||
String templateCode = RandomUtils.randomString();
|
||||
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
|
||||
.put("op", "login").build();
|
||||
Collection<String> toMails = Lists.newArrayList("admin@test.com");
|
||||
Collection<String> ccMails = Lists.newArrayList("cc@test.com");
|
||||
Collection<String> bccMails = Lists.newArrayList("bcc@test.com");
|
||||
|
||||
// mock adminUserService 的方法
|
||||
AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setMobile("15601691300"));
|
||||
AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setEmail("admin@example.com"));
|
||||
when(adminUserService.getUser(eq(userId))).thenReturn(user);
|
||||
|
||||
// mock MailTemplateService 的方法
|
||||
@@ -93,61 +98,27 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account);
|
||||
// mock MailLogService 的方法
|
||||
Long mailLogId = randomLongId();
|
||||
when(mailLogService.createMailLog(eq(userId), eq(UserTypeEnum.ADMIN.getValue()), eq(user.getEmail()),
|
||||
when(mailLogService.createMailLog(eq(userId), eq(UserTypeEnum.ADMIN.getValue()),
|
||||
argThat(toMailSet -> toMailSet.contains(user.getEmail()) && toMailSet.contains("admin@test.com")),
|
||||
argThat(ccMailSet -> ccMailSet.contains("cc@test.com")),
|
||||
argThat(bccMailSet -> bccMailSet.contains("bcc@test.com")),
|
||||
eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId);
|
||||
|
||||
// 调用
|
||||
Long resultMailLogId = mailSendService.sendSingleMailToAdmin(null, userId, templateCode, templateParams);
|
||||
Long resultMailLogId = mailSendService.sendSingleMail(toMails, ccMails, bccMails, userId,
|
||||
UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
|
||||
// 断言
|
||||
assertEquals(mailLogId, resultMailLogId);
|
||||
// 断言调用
|
||||
verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(user.getEmail()),
|
||||
eq(account.getId()), eq(template.getNickname()), eq(title), eq(content));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendSingleMailToMember() {
|
||||
// 准备参数
|
||||
Long userId = randomLongId();
|
||||
String templateCode = RandomUtils.randomString();
|
||||
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
|
||||
.put("op", "login").build();
|
||||
// mock memberService 的方法
|
||||
String mail = randomEmail();
|
||||
when(memberService.getMemberUserEmail(eq(userId))).thenReturn(mail);
|
||||
|
||||
// mock MailTemplateService 的方法
|
||||
MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> {
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setContent("验证码为{code}, 操作为{op}");
|
||||
o.setParams(Lists.newArrayList("code", "op"));
|
||||
});
|
||||
when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
|
||||
String title = RandomUtils.randomString();
|
||||
when(mailTemplateService.formatMailTemplateContent(eq(template.getTitle()), eq(templateParams)))
|
||||
.thenReturn(title);
|
||||
String content = RandomUtils.randomString();
|
||||
when(mailTemplateService.formatMailTemplateContent(eq(template.getContent()), eq(templateParams)))
|
||||
.thenReturn(content);
|
||||
// mock MailAccountService 的方法
|
||||
MailAccountDO account = randomPojo(MailAccountDO.class);
|
||||
when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account);
|
||||
// mock MailLogService 的方法
|
||||
Long mailLogId = randomLongId();
|
||||
when(mailLogService.createMailLog(eq(userId), eq(UserTypeEnum.MEMBER.getValue()), eq(mail),
|
||||
eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId);
|
||||
|
||||
// 调用
|
||||
Long resultMailLogId = mailSendService.sendSingleMailToMember(null, userId, templateCode, templateParams);
|
||||
// 断言
|
||||
assertEquals(mailLogId, resultMailLogId);
|
||||
// 断言调用
|
||||
verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(mail),
|
||||
verify(mailProducer).sendMailSendMessage(eq(mailLogId),
|
||||
argThat(toMailSet -> toMailSet.contains(user.getEmail()) && toMailSet.contains("admin@test.com")),
|
||||
argThat(ccMailSet -> ccMailSet.contains("cc@test.com")),
|
||||
argThat(bccMailSet -> bccMailSet.contains("bcc@test.com")),
|
||||
eq(account.getId()), eq(template.getNickname()), eq(title), eq(content));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送成功,当短信模板开启时
|
||||
* 发送成功,当邮件模板开启时
|
||||
*/
|
||||
@Test
|
||||
public void testSendSingleMail_successWhenMailTemplateEnable() {
|
||||
@@ -158,6 +129,8 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
String templateCode = RandomUtils.randomString();
|
||||
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
|
||||
.put("op", "login").build();
|
||||
Collection<String> toMails = Lists.newArrayList(mail);
|
||||
|
||||
// mock MailTemplateService 的方法
|
||||
MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> {
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
@@ -176,23 +149,29 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account);
|
||||
// mock MailLogService 的方法
|
||||
Long mailLogId = randomLongId();
|
||||
when(mailLogService.createMailLog(eq(userId), eq(userType), eq(mail),
|
||||
when(mailLogService.createMailLog(eq(userId), eq(userType),
|
||||
argThat(toMailSet -> toMailSet.contains(mail)),
|
||||
argThat(Collection::isEmpty),
|
||||
argThat(Collection::isEmpty),
|
||||
eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId);
|
||||
|
||||
// 调用
|
||||
Long resultMailLogId = mailSendService.sendSingleMail(mail, userId, userType, templateCode, templateParams);
|
||||
Long resultMailLogId = mailSendService.sendSingleMail(toMails, null, null, userId, userType, templateCode, templateParams);
|
||||
// 断言
|
||||
assertEquals(mailLogId, resultMailLogId);
|
||||
// 断言调用
|
||||
verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(mail),
|
||||
verify(mailProducer).sendMailSendMessage(eq(mailLogId),
|
||||
argThat(toMailSet -> toMailSet.contains(mail)),
|
||||
argThat(Collection::isEmpty),
|
||||
argThat(Collection::isEmpty),
|
||||
eq(account.getId()), eq(template.getNickname()), eq(title), eq(content));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送成功,当短信模板关闭时
|
||||
* 发送成功,当邮件模板关闭时
|
||||
*/
|
||||
@Test
|
||||
public void testSendSingleMail_successWhenSmsTemplateDisable() {
|
||||
public void testSendSingleMail_successWhenMailTemplateDisable() {
|
||||
// 准备参数
|
||||
String mail = randomEmail();
|
||||
Long userId = randomLongId();
|
||||
@@ -200,6 +179,8 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
String templateCode = RandomUtils.randomString();
|
||||
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
|
||||
.put("op", "login").build();
|
||||
Collection<String> toMails = Lists.newArrayList(mail);
|
||||
|
||||
// mock MailTemplateService 的方法
|
||||
MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> {
|
||||
o.setStatus(CommonStatusEnum.DISABLE.getStatus());
|
||||
@@ -218,15 +199,18 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account);
|
||||
// mock MailLogService 的方法
|
||||
Long mailLogId = randomLongId();
|
||||
when(mailLogService.createMailLog(eq(userId), eq(userType), eq(mail),
|
||||
when(mailLogService.createMailLog(eq(userId), eq(userType),
|
||||
argThat(toMailSet -> toMailSet.contains(mail)),
|
||||
argThat(Collection::isEmpty),
|
||||
argThat(Collection::isEmpty),
|
||||
eq(account), eq(template), eq(content), eq(templateParams), eq(false))).thenReturn(mailLogId);
|
||||
|
||||
// 调用
|
||||
Long resultMailLogId = mailSendService.sendSingleMail(mail, userId, userType, templateCode, templateParams);
|
||||
Long resultMailLogId = mailSendService.sendSingleMail(toMails, null, null, userId, userType, templateCode, templateParams);
|
||||
// 断言
|
||||
assertEquals(mailLogId, resultMailLogId);
|
||||
// 断言调用
|
||||
verify(mailProducer, times(0)).sendMailSendMessage(anyLong(), anyString(),
|
||||
verify(mailProducer, times(0)).sendMailSendMessage(anyLong(), any(), any(), any(),
|
||||
anyLong(), anyString(), anyString(), anyString());
|
||||
}
|
||||
|
||||
@@ -255,12 +239,29 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateMail_notExists() {
|
||||
public void testSendSingleMail_noValidEmail() {
|
||||
// 准备参数
|
||||
// mock 方法
|
||||
Long userId = randomLongId();
|
||||
String templateCode = RandomUtils.randomString();
|
||||
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
|
||||
.put("op", "login").build();
|
||||
Collection<String> toMails = Lists.newArrayList("invalid-email"); // 非法邮箱
|
||||
|
||||
// mock MailTemplateService 的方法
|
||||
MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> {
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setContent("验证码为{code}, 操作为{op}");
|
||||
o.setParams(Lists.newArrayList("code", "op"));
|
||||
});
|
||||
when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
|
||||
|
||||
// mock MailAccountService 的方法
|
||||
MailAccountDO account = randomPojo(MailAccountDO.class);
|
||||
when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account);
|
||||
|
||||
// 调用,并断言异常
|
||||
assertServiceException(() -> mailSendService.validateMail(null),
|
||||
assertServiceException(() -> mailSendService.sendSingleMail(toMails, null, null, userId,
|
||||
UserTypeEnum.ADMIN.getValue(), templateCode, templateParams),
|
||||
MAIL_SEND_MAIL_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@@ -286,7 +287,8 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
assertEquals(account.getPort(), mailAccount.getPort());
|
||||
assertEquals(account.getSslEnable(), mailAccount.isSslEnable());
|
||||
return true;
|
||||
}), eq(message.getMail()), eq(message.getTitle()), eq(message.getContent()), eq(true)))
|
||||
}), eq(message.getToMails()), eq(message.getCcMails()), eq(message.getBccMails()),
|
||||
eq(message.getTitle()), eq(message.getContent()), eq(true)))
|
||||
.thenReturn(messageId);
|
||||
|
||||
// 调用
|
||||
@@ -317,7 +319,8 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
assertEquals(account.getPort(), mailAccount.getPort());
|
||||
assertEquals(account.getSslEnable(), mailAccount.isSslEnable());
|
||||
return true;
|
||||
}), eq(message.getMail()), eq(message.getTitle()), eq(message.getContent()), eq(true))).thenThrow(e);
|
||||
}), eq(message.getToMails()), eq(message.getCcMails()), eq(message.getBccMails()),
|
||||
eq(message.getTitle()), eq(message.getContent()), eq(true))).thenThrow(e);
|
||||
|
||||
// 调用
|
||||
mailSendService.doSendMail(message);
|
||||
|
||||
@@ -553,7 +553,9 @@ CREATE TABLE IF NOT EXISTS "system_mail_log" (
|
||||
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
"user_id" bigint,
|
||||
"user_type" varchar,
|
||||
"to_mail" varchar NOT NULL,
|
||||
"to_mails" varchar NOT NULL,
|
||||
"cc_mails" varchar,
|
||||
"bcc_mails" varchar,
|
||||
"account_id" bigint NOT NULL,
|
||||
"from_mail" varchar NOT NULL,
|
||||
"template_id" bigint NOT NULL,
|
||||
|
||||
Reference in New Issue
Block a user