mirror of
https://gitee.com/yudaocode/yudao-boot-mini.git
synced 2026-03-22 05:27:15 +08:00
Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
# Conflicts: # yudao-module-ai/pom.xml # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/segment/AiKnowledgeSegmentPageReqVO.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmCopyTaskDelegate.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java # yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java # yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue2Test.java # yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue3Test.java # yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java # yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java # yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/kefu/vo/message/KeFuMessageListReqVO.java # yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/kefu/vo/message/AppKeFuMessagePageReqVO.java # yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java # yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java # yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java # yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java # yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersale/core/aop/AfterSaleLogAspect.java # yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java # yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/MemberUserController.java # yudao-module-pay/pom.xml # yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferCreateReqDTO.java # yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/wallet/PayWalletRechargeController.java # yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java # yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeService.java # yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java # yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImplTest.java # yudao-module-system/src/test/resources/sql/create_tables.sql
This commit is contained in:
@@ -85,7 +85,7 @@ public class SocialClientApiImpl implements SocialClientApi {
|
||||
// 2. 获得社交用户
|
||||
SocialUserRespDTO socialUser = socialUserService.getSocialUserByUserId(reqDTO.getUserType(), reqDTO.getUserId(),
|
||||
SocialTypeEnum.WECHAT_MINI_PROGRAM.getType());
|
||||
if (StrUtil.isBlankIfStr(socialUser.getOpenid())) {
|
||||
if (ObjUtil.isNull(socialUser) || StrUtil.isBlankIfStr(socialUser.getOpenid())) {
|
||||
log.warn("[sendWxaSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:会员 openid 缺失]", reqDTO);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,14 @@ public class PostController {
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("delete-list")
|
||||
@Operation(summary = "批量删除岗位")
|
||||
@PreAuthorize("@ss.hasPermission('system:post:delete')")
|
||||
public CommonResult<Boolean> deletePostList(@RequestParam("ids") List<Long> ids) {
|
||||
postService.deletePostList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/get")
|
||||
@Operation(summary = "获得岗位信息")
|
||||
@Parameter(name = "id", description = "岗位编号", required = true, example = "1024")
|
||||
|
||||
@@ -36,6 +36,14 @@ public class LoginLogController {
|
||||
@Resource
|
||||
private LoginLogService loginLogService;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得登录日志")
|
||||
@PreAuthorize("@ss.hasPermission('system:login-log:query')")
|
||||
public CommonResult<LoginLogRespVO> getLoginLog(Long id) {
|
||||
LoginLogDO loginLog = loginLogService.getLoginLog(id);
|
||||
return success(BeanUtils.toBean(loginLog, LoginLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得登录日志分页列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:login-log:query')")
|
||||
|
||||
@@ -13,11 +13,13 @@ import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO;
|
||||
import cn.iocoder.yudao.module.system.service.logger.OperateLogService;
|
||||
import com.fhs.core.trans.anno.TransMethodResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -38,6 +40,15 @@ public class OperateLogController {
|
||||
@Resource
|
||||
private OperateLogService operateLogService;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "查看操作日志")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:operate-log:query')")
|
||||
public CommonResult<OperateLogRespVO> getOperateLog(@RequestParam("id") Long id) {
|
||||
OperateLogDO operateLog = operateLogService.getOperateLog(id);
|
||||
return success(BeanUtils.toBean(operateLog, OperateLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "查看操作日志分页列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:operate-log:query')")
|
||||
@@ -50,6 +61,7 @@ public class OperateLogController {
|
||||
@Operation(summary = "导出操作日志")
|
||||
@GetMapping("/export-excel")
|
||||
@PreAuthorize("@ss.hasPermission('system:operate-log:export')")
|
||||
@TransMethodResult
|
||||
@ApiAccessLog(operateType = EXPORT)
|
||||
public void exportOperateLog(HttpServletResponse response, @Valid OperateLogPageReqVO exportReqVO) throws IOException {
|
||||
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog;
|
||||
|
||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
|
||||
import com.fhs.core.trans.anno.Trans;
|
||||
import com.fhs.core.trans.constant.TransType;
|
||||
import com.fhs.core.trans.vo.VO;
|
||||
@@ -31,6 +33,11 @@ public class OperateLogRespVO implements VO {
|
||||
@ExcelProperty("操作人")
|
||||
private String userName;
|
||||
|
||||
@Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1", implementation = Integer.class)
|
||||
@ExcelProperty("用户类型")
|
||||
@DictFormat(DictTypeConstants.USER_TYPE)
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "操作模块类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单")
|
||||
@ExcelProperty("操作模块类型")
|
||||
private String type;
|
||||
|
||||
@@ -11,10 +11,12 @@ import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogRespVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO;
|
||||
import cn.iocoder.yudao.module.system.service.sms.SmsLogService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@@ -44,6 +46,15 @@ public class SmsLogController {
|
||||
return success(BeanUtils.toBean(pageResult, SmsLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得短信日志")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:sms-log:query')")
|
||||
public CommonResult<SmsLogRespVO> getSmsLog(@RequestParam("id") Long id) {
|
||||
SmsLogDO smsLog = smsLogService.getSmsLog(id);
|
||||
return success(BeanUtils.toBean(smsLog, SmsLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出短信日志 Excel")
|
||||
@PreAuthorize("@ss.hasPermission('system:sms-log:export')")
|
||||
|
||||
@@ -27,9 +27,12 @@ public class SocialClientRespVO {
|
||||
@Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "peter")
|
||||
private String clientSecret;
|
||||
|
||||
@Schema(description = "授权方的网页应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045")
|
||||
@Schema(description = "授权方的网页应用编号", example = "2000045")
|
||||
private String agentId;
|
||||
|
||||
@Schema(description = "publicKey 公钥", example = "2000045")
|
||||
private String publicKey;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
|
||||
@@ -45,6 +45,9 @@ public class SocialClientSaveReqVO {
|
||||
@Schema(description = "授权方的网页应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000045")
|
||||
private String agentId;
|
||||
|
||||
@Schema(description = "publicKey 公钥", example = "2000045")
|
||||
private String publicKey;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "状态不能为空")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
@@ -58,4 +61,12 @@ public class SocialClientSaveReqVO {
|
||||
|| !StrUtil.isEmpty(agentId);
|
||||
}
|
||||
|
||||
@AssertTrue(message = "publicKey 不能为空")
|
||||
@JsonIgnore
|
||||
public boolean isPublicKeyValid() {
|
||||
// 如果是支付宝,必须填写 publicKey 属性
|
||||
return !Objects.equals(socialType, SocialTypeEnum.ALIPAY_MINI_PROGRAM.getType())
|
||||
|| !StrUtil.isEmpty(publicKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthSmsLoginReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthSmsSendReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthSocialLoginReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||
@@ -26,8 +28,6 @@ public interface AuthConvert {
|
||||
|
||||
AuthConvert INSTANCE = Mappers.getMapper(AuthConvert.class);
|
||||
|
||||
AuthLoginRespVO convert(OAuth2AccessTokenDO bean);
|
||||
|
||||
default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) {
|
||||
return AuthPermissionInfoRespVO.builder()
|
||||
.user(BeanUtils.toBean(user, AuthPermissionInfoRespVO.UserVO.class))
|
||||
|
||||
@@ -73,4 +73,12 @@ public class SocialClientDO extends TenantBaseDO {
|
||||
*/
|
||||
private String agentId;
|
||||
|
||||
/**
|
||||
* publicKey 公钥
|
||||
*
|
||||
* 目前只有部分“社交类型”在使用:
|
||||
* 1. 支付宝:支付宝公钥
|
||||
*/
|
||||
private String publicKey;
|
||||
|
||||
}
|
||||
|
||||
@@ -53,6 +53,12 @@ public enum SocialTypeEnum implements ArrayValuable<Integer> {
|
||||
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html">接入文档</a>
|
||||
*/
|
||||
WECHAT_MINI_PROGRAM(34, "WECHAT_MINI_PROGRAM"),
|
||||
/**
|
||||
* 支付宝小程序
|
||||
*
|
||||
* @see <a href="https://opendocs.alipay.com/mini/05dxgc?pathHash=1a3ecb13">接入文档</a>
|
||||
*/
|
||||
ALIPAY_MINI_PROGRAM(40, "ALIPAY"),
|
||||
;
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values()).map(SocialTypeEnum::getType).toArray(Integer[]::new);
|
||||
|
||||
@@ -91,10 +91,10 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||
@Override
|
||||
public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable {
|
||||
// 1. 执行请求
|
||||
// 参考链接 https://api.aliyun.com/document/Dysmsapi/2017-05-25/QuerySmsTemplate
|
||||
// 参考链接 https://api.aliyun.com/document/Dysmsapi/2017-05-25/GetSmsTemplate
|
||||
TreeMap<String, Object> queryParam = new TreeMap<>();
|
||||
queryParam.put("TemplateCode", apiTemplateId);
|
||||
JSONObject response = request("QuerySmsTemplate", queryParam);
|
||||
JSONObject response = request("GetSmsTemplate", queryParam);
|
||||
|
||||
// 2.1 请求失败
|
||||
String code = response.getStr("Code");
|
||||
|
||||
@@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
|
||||
@@ -215,13 +216,13 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
||||
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(userId, getUserType().getValue(),
|
||||
OAuth2ClientConstants.CLIENT_ID_DEFAULT, null);
|
||||
// 构建返回结果
|
||||
return AuthConvert.INSTANCE.convert(accessTokenDO);
|
||||
return BeanUtils.toBean(accessTokenDO, AuthLoginRespVO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthLoginRespVO refreshToken(String refreshToken) {
|
||||
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, OAuth2ClientConstants.CLIENT_ID_DEFAULT);
|
||||
return AuthConvert.INSTANCE.convert(accessTokenDO);
|
||||
return BeanUtils.toBean(accessTokenDO, AuthLoginRespVO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,6 +12,14 @@ import javax.validation.Valid;
|
||||
*/
|
||||
public interface LoginLogService {
|
||||
|
||||
/**
|
||||
* 获得登录日志
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 登录日志
|
||||
*/
|
||||
LoginLogDO getLoginLog(Long id);
|
||||
|
||||
/**
|
||||
* 获得登录日志分页
|
||||
*
|
||||
|
||||
@@ -21,6 +21,11 @@ public class LoginLogServiceImpl implements LoginLogService {
|
||||
@Resource
|
||||
private LoginLogMapper loginLogMapper;
|
||||
|
||||
@Override
|
||||
public LoginLogDO getLoginLog(Long id) {
|
||||
return loginLogMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<LoginLogDO> getLoginLogPage(LoginLogPageReqVO pageReqVO) {
|
||||
return loginLogMapper.selectPage(pageReqVO);
|
||||
|
||||
@@ -20,6 +20,14 @@ public interface OperateLogService {
|
||||
*/
|
||||
void createOperateLog(OperateLogCreateReqDTO createReqDTO);
|
||||
|
||||
/**
|
||||
* 获得操作日志
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 操作日志
|
||||
*/
|
||||
OperateLogDO getOperateLog(Long id);
|
||||
|
||||
/**
|
||||
* 获得操作日志分页列表
|
||||
*
|
||||
|
||||
@@ -32,6 +32,11 @@ public class OperateLogServiceImpl implements OperateLogService {
|
||||
operateLogMapper.insert(log);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OperateLogDO getOperateLog(Long id) {
|
||||
return operateLogMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<OperateLogDO> getOperateLogPage(OperateLogPageReqVO pageReqVO) {
|
||||
return operateLogMapper.selectPage(pageReqVO);
|
||||
|
||||
@@ -19,8 +19,10 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
@@ -53,7 +55,7 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
|
||||
// 插入
|
||||
MailTemplateDO template = BeanUtils.toBean(createReqVO, MailTemplateDO.class)
|
||||
.setParams(parseTemplateContentParams(createReqVO.getContent()));
|
||||
.setParams(parseTemplateTitleAndContentParams(createReqVO.getTitle(), createReqVO.getContent()));
|
||||
mailTemplateMapper.insert(template);
|
||||
return template.getId();
|
||||
}
|
||||
@@ -69,7 +71,7 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
|
||||
// 更新
|
||||
MailTemplateDO updateObj = BeanUtils.toBean(updateReqVO, MailTemplateDO.class)
|
||||
.setParams(parseTemplateContentParams(updateReqVO.getContent()));
|
||||
.setParams(parseTemplateTitleAndContentParams(updateReqVO.getTitle(), updateReqVO.getContent()));
|
||||
mailTemplateMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@@ -129,7 +131,77 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
|
||||
@Override
|
||||
public String formatMailTemplateContent(String content, Map<String, Object> params) {
|
||||
return StrUtil.format(content, params);
|
||||
// 1. 先替换模板变量
|
||||
String formattedContent = StrUtil.format(content, params);
|
||||
|
||||
// 关联 Pull Request:https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1461 讨论
|
||||
// 2.1 反转义HTML特殊字符
|
||||
formattedContent = unescapeHtml(formattedContent);
|
||||
// 2.2 处理代码块(确保<pre><code>标签格式正确)
|
||||
formattedContent = formatHtmlCodeBlocks(formattedContent);
|
||||
// 2.3 将最外层的 pre 标签替换为 div 标签
|
||||
formattedContent = replaceOuterPreWithDiv(formattedContent);
|
||||
return formattedContent;
|
||||
}
|
||||
|
||||
private String replaceOuterPreWithDiv(String content) {
|
||||
if (StrUtil.isEmpty(content)) {
|
||||
return content;
|
||||
}
|
||||
// 使用正则表达式匹配所有的 <pre> 标签,包括嵌套的 <code> 标签
|
||||
String regex = "(?s)<pre[^>]*>(.*?)</pre>";
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(content);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
// 提取 <pre> 标签内的内容
|
||||
String innerContent = matcher.group(1);
|
||||
// 返回 div 标签包裹的内容
|
||||
matcher.appendReplacement(sb, "<div>" + innerContent + "</div>");
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 反转义 HTML 特殊字符
|
||||
*
|
||||
* @param input 输入字符串
|
||||
* @return 反转义后的字符串
|
||||
*/
|
||||
private String unescapeHtml(String input) {
|
||||
if (StrUtil.isEmpty(input)) {
|
||||
return input;
|
||||
}
|
||||
return input
|
||||
.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace(""", "\"")
|
||||
.replace("'", "'")
|
||||
.replace(" ", " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化 HTML 中的代码块
|
||||
*
|
||||
* @param content 邮件内容
|
||||
* @return 格式化后的邮件内容
|
||||
*/
|
||||
private String formatHtmlCodeBlocks(String content) {
|
||||
// 匹配 <pre><code> 标签的代码块
|
||||
Pattern codeBlockPattern = Pattern.compile("<pre\\s*.*?><code\\s*.*?>(.*?)</code></pre>", Pattern.DOTALL);
|
||||
Matcher matcher = codeBlockPattern.matcher(content);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
// 获取代码块内容
|
||||
String codeBlock = matcher.group(1);
|
||||
// 为代码块添加样式
|
||||
String replacement = "<pre style=\"background-color: #f5f5f5; padding: 10px; border-radius: 5px; overflow-x: auto;\"><code>" + codeBlock + "</code></pre>";
|
||||
matcher.appendReplacement(sb, replacement);
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,14 +209,31 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
return mailTemplateMapper.selectCountByAccountId(accountId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析标题和内容中的参数
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public List<String> parseTemplateTitleAndContentParams(String title, String content) {
|
||||
List<String> titleParams = ReUtil.findAllGroup1(PATTERN_PARAMS, title);
|
||||
List<String> contentParams = ReUtil.findAllGroup1(PATTERN_PARAMS, content);
|
||||
// 合并参数并去重
|
||||
List<String> allParams = new ArrayList<>(titleParams);
|
||||
for (String param : contentParams) {
|
||||
if (!allParams.contains(param)) {
|
||||
allParams.add(param);
|
||||
}
|
||||
}
|
||||
return allParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得邮件模板中的参数,形如 {key}
|
||||
*
|
||||
* @param content 内容
|
||||
* @return 参数列表
|
||||
*/
|
||||
private List<String> parseTemplateContentParams(String content) {
|
||||
List<String> parseTemplateContentParams(String content) {
|
||||
return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -180,7 +180,13 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||
.setClientId(clientDO.getClientId()).setScopes(refreshTokenDO.getScopes())
|
||||
.setRefreshToken(refreshTokenDO.getRefreshToken())
|
||||
.setExpiresTime(LocalDateTime.now().plusSeconds(clientDO.getAccessTokenValiditySeconds()));
|
||||
accessTokenDO.setTenantId(TenantContextHolder.getTenantId()); // 手动设置租户编号,避免缓存到 Redis 的时候,无对应的租户编号
|
||||
// 优先从 refreshToken 获取租户编号,避免 ThreadLocal 被污染时导致 tenantId 为 null
|
||||
// 可能关联的 issue:https://t.zsxq.com/JIi5G
|
||||
Long tenantId = refreshTokenDO.getTenantId();
|
||||
if (tenantId == null) {
|
||||
tenantId = TenantContextHolder.getTenantId();
|
||||
}
|
||||
accessTokenDO.setTenantId(tenantId);
|
||||
oauth2AccessTokenMapper.insert(accessTokenDO);
|
||||
// 记录到 Redis 中
|
||||
oauth2AccessTokenRedisDAO.set(accessTokenDO);
|
||||
|
||||
@@ -255,6 +255,9 @@ 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);
|
||||
}
|
||||
@@ -277,7 +280,7 @@ public class MenuServiceImpl implements MenuService {
|
||||
}
|
||||
// 如果 id 为空,说明不用比较是否为相同 id 的菜单
|
||||
if (id == null) {
|
||||
return;
|
||||
throw exception(MENU_COMPONENT_NAME_DUPLICATE);
|
||||
}
|
||||
if (!menu.getId().equals(id)) {
|
||||
throw exception(MENU_COMPONENT_NAME_DUPLICATE);
|
||||
|
||||
@@ -58,6 +58,14 @@ public interface SmsLogService {
|
||||
void updateSmsReceiveResult(Long id, String apiSerialNo, Boolean success,
|
||||
LocalDateTime receiveTime, String apiReceiveCode, String apiReceiveMsg);
|
||||
|
||||
/**
|
||||
* 获得短信日志
|
||||
*
|
||||
* @param id 日志编号
|
||||
* @return 短信日志
|
||||
*/
|
||||
SmsLogDO getSmsLog(Long id);
|
||||
|
||||
/**
|
||||
* 获得短信日志分页
|
||||
*
|
||||
|
||||
@@ -78,6 +78,11 @@ public class SmsLogServiceImpl implements SmsLogService {
|
||||
.receiveTime(receiveTime).apiReceiveCode(apiReceiveCode).apiReceiveMsg(apiReceiveMsg).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsLogDO getSmsLog(Long id) {
|
||||
return smsLogMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<SmsLogDO> getSmsLogPage(SmsLogPageReqVO pageReqVO) {
|
||||
return smsLogMapper.selectPage(pageReqVO);
|
||||
|
||||
@@ -50,6 +50,7 @@ import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.request.AuthAlipayRequest;
|
||||
import me.zhyd.oauth.request.AuthRequest;
|
||||
import me.zhyd.oauth.utils.AuthStateUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -168,7 +169,7 @@ public class SocialClientServiceImpl implements SocialClientService {
|
||||
public AuthUser getAuthUser(Integer socialType, Integer userType, String code, String state) {
|
||||
// 构建请求
|
||||
AuthRequest authRequest = buildAuthRequest(socialType, userType);
|
||||
AuthCallback authCallback = AuthCallback.builder().code(code).state(state).build();
|
||||
AuthCallback authCallback = AuthCallback.builder().code(code).auth_code(code).state(state).build();
|
||||
// 执行请求
|
||||
AuthResponse<?> authResponse = authRequest.login(authCallback);
|
||||
log.info("[getAuthUser][请求社交平台 type({}) request({}) response({})]", socialType,
|
||||
@@ -204,7 +205,15 @@ public class SocialClientServiceImpl implements SocialClientService {
|
||||
if (client.getAgentId() != null) { // 如果有 agentId 则修改 agentId
|
||||
newAuthConfig.setAgentId(client.getAgentId());
|
||||
}
|
||||
// 如果是阿里的小程序
|
||||
if (SocialTypeEnum.ALIPAY_MINI_PROGRAM.getType().equals(socialType)) {
|
||||
return new AuthAlipayRequest(newAuthConfig, client.getPublicKey());
|
||||
}
|
||||
// 2.3 设置会 request 里,进行后续使用
|
||||
if (SocialTypeEnum.ALIPAY_MINI_PROGRAM.getType().equals(socialType)) {
|
||||
// 特殊:如果是支付宝的小程序,多了 publicKey 属性,可见 AuthConfig 里的 alipayPublicKey 字段说明
|
||||
return new AuthAlipayRequest(newAuthConfig, client.getPublicKey());
|
||||
}
|
||||
ReflectUtil.setFieldValue(request, "config", newAuthConfig);
|
||||
}
|
||||
return request;
|
||||
|
||||
Reference in New Issue
Block a user