Commit bda892277df5e14541f5c2426b20868b4d882d8e
1 parent
bb9a2b53
fix(im):加固管理端入参和统计边界
- 校验敏感词、表情包、表情项状态枚举和批量删除数量上限 - 限制私聊、群聊增量拉取 size 最小值 - 收紧表情包项 Mapper 的 in 查询并在 Service 层处理空好友集合 - 兼容统计聚合数值类型并明确当前有效群总数口径 - 固定 LiveKit token 签名编码和 IM web 包说明 - 修正群禁言权限错误码顺序并补充封禁、踢人、禁言回归测试 - 流转 IM bug 文档并记录本轮不修项语义
Showing
21 changed files
with
147 additions
and
31 deletions
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFacePackItemManagerController.java
| @@ -13,6 +13,7 @@ import io.swagger.v3.oas.annotations.Parameter; | @@ -13,6 +13,7 @@ import io.swagger.v3.oas.annotations.Parameter; | ||
| 13 | import io.swagger.v3.oas.annotations.tags.Tag; | 13 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 14 | import jakarta.annotation.Resource; | 14 | import jakarta.annotation.Resource; |
| 15 | import jakarta.validation.Valid; | 15 | import jakarta.validation.Valid; |
| 16 | +import jakarta.validation.constraints.Size; | ||
| 16 | import org.springframework.security.access.prepost.PreAuthorize; | 17 | import org.springframework.security.access.prepost.PreAuthorize; |
| 17 | import org.springframework.validation.annotation.Validated; | 18 | import org.springframework.validation.annotation.Validated; |
| 18 | import org.springframework.web.bind.annotation.*; | 19 | import org.springframework.web.bind.annotation.*; |
| @@ -58,7 +59,8 @@ public class ImFacePackItemManagerController { | @@ -58,7 +59,8 @@ public class ImFacePackItemManagerController { | ||
| 58 | @Operation(summary = "批量删除表情") | 59 | @Operation(summary = "批量删除表情") |
| 59 | @Parameter(name = "ids", description = "编号列表", required = true) | 60 | @Parameter(name = "ids", description = "编号列表", required = true) |
| 60 | @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:delete')") | 61 | @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:delete')") |
| 61 | - public CommonResult<Boolean> deleteFacePackItemList(@RequestParam("ids") List<Long> ids) { | 62 | + public CommonResult<Boolean> deleteFacePackItemList(@RequestParam("ids") |
| 63 | + @Size(max = 100, message = "批量删除最多 100 条") List<Long> ids) { | ||
| 62 | facePackItemService.deleteFacePackItemList(ids); | 64 | facePackItemService.deleteFacePackItemList(ids); |
| 63 | return success(true); | 65 | return success(true); |
| 64 | } | 66 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFacePackManagerController.java
| @@ -13,6 +13,7 @@ import io.swagger.v3.oas.annotations.Parameter; | @@ -13,6 +13,7 @@ import io.swagger.v3.oas.annotations.Parameter; | ||
| 13 | import io.swagger.v3.oas.annotations.tags.Tag; | 13 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 14 | import jakarta.annotation.Resource; | 14 | import jakarta.annotation.Resource; |
| 15 | import jakarta.validation.Valid; | 15 | import jakarta.validation.Valid; |
| 16 | +import jakarta.validation.constraints.Size; | ||
| 16 | import org.springframework.security.access.prepost.PreAuthorize; | 17 | import org.springframework.security.access.prepost.PreAuthorize; |
| 17 | import org.springframework.validation.annotation.Validated; | 18 | import org.springframework.validation.annotation.Validated; |
| 18 | import org.springframework.web.bind.annotation.*; | 19 | import org.springframework.web.bind.annotation.*; |
| @@ -58,7 +59,8 @@ public class ImFacePackManagerController { | @@ -58,7 +59,8 @@ public class ImFacePackManagerController { | ||
| 58 | @Operation(summary = "批量删除表情包") | 59 | @Operation(summary = "批量删除表情包") |
| 59 | @Parameter(name = "ids", description = "编号列表", required = true) | 60 | @Parameter(name = "ids", description = "编号列表", required = true) |
| 60 | @PreAuthorize("@ss.hasPermission('im:manager:face-pack:delete')") | 61 | @PreAuthorize("@ss.hasPermission('im:manager:face-pack:delete')") |
| 61 | - public CommonResult<Boolean> deleteFacePackList(@RequestParam("ids") List<Long> ids) { | 62 | + public CommonResult<Boolean> deleteFacePackList(@RequestParam("ids") |
| 63 | + @Size(max = 100, message = "批量删除最多 100 条") List<Long> ids) { | ||
| 62 | facePackService.deleteFacePackList(ids); | 64 | facePackService.deleteFacePackList(ids); |
| 63 | return success(true); | 65 | return success(true); |
| 64 | } | 66 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemPageReqVO.java
| 1 | package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item; | 1 | package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 5 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 4 | import io.swagger.v3.oas.annotations.media.Schema; | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | import lombok.Data; | 7 | import lombok.Data; |
| 6 | import lombok.EqualsAndHashCode; | 8 | import lombok.EqualsAndHashCode; |
| @@ -17,6 +19,7 @@ public class ImFacePackItemPageReqVO extends PageParam { | @@ -17,6 +19,7 @@ public class ImFacePackItemPageReqVO extends PageParam { | ||
| 17 | private String name; | 19 | private String name; |
| 18 | 20 | ||
| 19 | @Schema(description = "状态", example = "0") | 21 | @Schema(description = "状态", example = "0") |
| 22 | + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") | ||
| 20 | private Integer status; // 参见 CommonStatusEnum 枚举类 | 23 | private Integer status; // 参见 CommonStatusEnum 枚举类 |
| 21 | 24 | ||
| 22 | } | 25 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemSaveReqVO.java
| 1 | package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item; | 1 | package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 4 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import jakarta.validation.constraints.Max; | 6 | import jakarta.validation.constraints.Max; |
| 5 | import jakarta.validation.constraints.Min; | 7 | import jakarta.validation.constraints.Min; |
| @@ -47,6 +49,7 @@ public class ImFacePackItemSaveReqVO { | @@ -47,6 +49,7 @@ public class ImFacePackItemSaveReqVO { | ||
| 47 | 49 | ||
| 48 | @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | 50 | @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| 49 | @NotNull(message = "状态不能为空") | 51 | @NotNull(message = "状态不能为空") |
| 52 | + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") | ||
| 50 | private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用) | 53 | private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用) |
| 51 | 54 | ||
| 52 | } | 55 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackPageReqVO.java
| 1 | package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack; | 1 | package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 5 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 4 | import io.swagger.v3.oas.annotations.media.Schema; | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | import lombok.Data; | 7 | import lombok.Data; |
| 6 | import lombok.EqualsAndHashCode; | 8 | import lombok.EqualsAndHashCode; |
| @@ -19,6 +21,7 @@ public class ImFacePackPageReqVO extends PageParam { | @@ -19,6 +21,7 @@ public class ImFacePackPageReqVO extends PageParam { | ||
| 19 | private String name; | 21 | private String name; |
| 20 | 22 | ||
| 21 | @Schema(description = "状态", example = "0") | 23 | @Schema(description = "状态", example = "0") |
| 24 | + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") | ||
| 22 | private Integer status; // 参见 CommonStatusEnum 枚举类 | 25 | private Integer status; // 参见 CommonStatusEnum 枚举类 |
| 23 | 26 | ||
| 24 | @Schema(description = "创建时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]") | 27 | @Schema(description = "创建时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]") |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackSaveReqVO.java
| 1 | package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack; | 1 | package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 4 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import jakarta.validation.constraints.NotBlank; | 6 | import jakarta.validation.constraints.NotBlank; |
| 5 | import jakarta.validation.constraints.NotNull; | 7 | import jakarta.validation.constraints.NotNull; |
| @@ -28,6 +30,7 @@ public class ImFacePackSaveReqVO { | @@ -28,6 +30,7 @@ public class ImFacePackSaveReqVO { | ||
| 28 | 30 | ||
| 29 | @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | 31 | @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| 30 | @NotNull(message = "状态不能为空") | 32 | @NotNull(message = "状态不能为空") |
| 33 | + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") | ||
| 31 | private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用) | 34 | private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用) |
| 32 | 35 | ||
| 33 | } | 36 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/ImSensitiveWordManagerController.java
| @@ -18,6 +18,7 @@ import io.swagger.v3.oas.annotations.Parameter; | @@ -18,6 +18,7 @@ import io.swagger.v3.oas.annotations.Parameter; | ||
| 18 | import io.swagger.v3.oas.annotations.tags.Tag; | 18 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 19 | import jakarta.annotation.Resource; | 19 | import jakarta.annotation.Resource; |
| 20 | import jakarta.validation.Valid; | 20 | import jakarta.validation.Valid; |
| 21 | +import jakarta.validation.constraints.Size; | ||
| 21 | import org.springframework.security.access.prepost.PreAuthorize; | 22 | import org.springframework.security.access.prepost.PreAuthorize; |
| 22 | import org.springframework.validation.annotation.Validated; | 23 | import org.springframework.validation.annotation.Validated; |
| 23 | import org.springframework.web.bind.annotation.*; | 24 | import org.springframework.web.bind.annotation.*; |
| @@ -67,7 +68,9 @@ public class ImSensitiveWordManagerController { | @@ -67,7 +68,9 @@ public class ImSensitiveWordManagerController { | ||
| 67 | @Operation(summary = "批量删除敏感词") | 68 | @Operation(summary = "批量删除敏感词") |
| 68 | @Parameter(name = "ids", description = "编号列表", required = true) | 69 | @Parameter(name = "ids", description = "编号列表", required = true) |
| 69 | @PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:delete')") | 70 | @PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:delete')") |
| 70 | - public CommonResult<Boolean> deleteSensitiveWordList(@RequestParam("ids") List<Long> ids) { | 71 | + public CommonResult<Boolean> deleteSensitiveWordList( |
| 72 | + @RequestParam("ids") | ||
| 73 | + @Size(max = 100, message = "批量删除最多 100 条") List<Long> ids) { | ||
| 71 | sensitiveWordService.deleteSensitiveWordList(ids); | 74 | sensitiveWordService.deleteSensitiveWordList(ids); |
| 72 | return success(true); | 75 | return success(true); |
| 73 | } | 76 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordPageReqVO.java
| 1 | package cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo; | 1 | package cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 5 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 4 | import io.swagger.v3.oas.annotations.media.Schema; | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | import lombok.Data; | 7 | import lombok.Data; |
| 6 | import lombok.EqualsAndHashCode; | 8 | import lombok.EqualsAndHashCode; |
| @@ -19,6 +21,7 @@ public class ImSensitiveWordPageReqVO extends PageParam { | @@ -19,6 +21,7 @@ public class ImSensitiveWordPageReqVO extends PageParam { | ||
| 19 | private String word; | 21 | private String word; |
| 20 | 22 | ||
| 21 | @Schema(description = "状态", example = "0") | 23 | @Schema(description = "状态", example = "0") |
| 24 | + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") | ||
| 22 | private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用) | 25 | private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用) |
| 23 | 26 | ||
| 24 | @Schema(description = "创建时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]") | 27 | @Schema(description = "创建时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]") |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordSaveReqVO.java
| 1 | package cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo; | 1 | package cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 4 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import jakarta.validation.constraints.NotBlank; | 6 | import jakarta.validation.constraints.NotBlank; |
| 5 | import jakarta.validation.constraints.NotNull; | 7 | import jakarta.validation.constraints.NotNull; |
| @@ -20,6 +22,7 @@ public class ImSensitiveWordSaveReqVO { | @@ -20,6 +22,7 @@ public class ImSensitiveWordSaveReqVO { | ||
| 20 | 22 | ||
| 21 | @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | 23 | @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| 22 | @NotNull(message = "状态不能为空") | 24 | @NotNull(message = "状态不能为空") |
| 25 | + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") | ||
| 23 | private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用) | 26 | private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用) |
| 24 | 27 | ||
| 25 | } | 28 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImGroupMessageController.java
| @@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.Parameter; | @@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.Parameter; | ||
| 12 | import io.swagger.v3.oas.annotations.tags.Tag; | 12 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 13 | import jakarta.annotation.Resource; | 13 | import jakarta.annotation.Resource; |
| 14 | import jakarta.validation.Valid; | 14 | import jakarta.validation.Valid; |
| 15 | +import jakarta.validation.constraints.Min; | ||
| 15 | import org.springframework.validation.annotation.Validated; | 16 | import org.springframework.validation.annotation.Validated; |
| 16 | import org.springframework.web.bind.annotation.*; | 17 | import org.springframework.web.bind.annotation.*; |
| 17 | 18 | ||
| @@ -40,8 +41,9 @@ public class ImGroupMessageController { | @@ -40,8 +41,9 @@ public class ImGroupMessageController { | ||
| 40 | @Operation(summary = "拉取群聊消息(增量)") | 41 | @Operation(summary = "拉取群聊消息(增量)") |
| 41 | @Parameter(name = "minId", description = "最小消息 id", required = true, example = "0") | 42 | @Parameter(name = "minId", description = "最小消息 id", required = true, example = "0") |
| 42 | @Parameter(name = "size", description = "拉取数量", required = true, example = "100") | 43 | @Parameter(name = "size", description = "拉取数量", required = true, example = "100") |
| 43 | - public CommonResult<List<ImGroupMessageRespVO>> pullGroupMessageList(@RequestParam("minId") Long minId, | ||
| 44 | - @RequestParam("size") Integer size) { | 44 | + public CommonResult<List<ImGroupMessageRespVO>> pullGroupMessageList( |
| 45 | + @RequestParam("minId") Long minId, | ||
| 46 | + @RequestParam("size") @Min(value = 1, message = "拉取数量最小值为 1") Integer size) { | ||
| 45 | List<ImGroupMessageDO> messages = groupMessageService.pullGroupMessageList(getLoginUserId(), minId, size); | 47 | List<ImGroupMessageDO> messages = groupMessageService.pullGroupMessageList(getLoginUserId(), minId, size); |
| 46 | return success(BeanUtils.toBean(messages, ImGroupMessageRespVO.class)); | 48 | return success(BeanUtils.toBean(messages, ImGroupMessageRespVO.class)); |
| 47 | } | 49 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImPrivateMessageController.java
| @@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.Parameter; | @@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.Parameter; | ||
| 12 | import io.swagger.v3.oas.annotations.tags.Tag; | 12 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 13 | import jakarta.annotation.Resource; | 13 | import jakarta.annotation.Resource; |
| 14 | import jakarta.validation.Valid; | 14 | import jakarta.validation.Valid; |
| 15 | +import jakarta.validation.constraints.Min; | ||
| 15 | import org.springframework.validation.annotation.Validated; | 16 | import org.springframework.validation.annotation.Validated; |
| 16 | import org.springframework.web.bind.annotation.*; | 17 | import org.springframework.web.bind.annotation.*; |
| 17 | 18 | ||
| @@ -41,8 +42,9 @@ public class ImPrivateMessageController { | @@ -41,8 +42,9 @@ public class ImPrivateMessageController { | ||
| 41 | @Operation(summary = "拉取私聊消息(增量)") | 42 | @Operation(summary = "拉取私聊消息(增量)") |
| 42 | @Parameter(name = "minId", description = "最小消息 id", required = true, example = "0") | 43 | @Parameter(name = "minId", description = "最小消息 id", required = true, example = "0") |
| 43 | @Parameter(name = "size", description = "拉取数量", required = true, example = "100") | 44 | @Parameter(name = "size", description = "拉取数量", required = true, example = "100") |
| 44 | - public CommonResult<List<ImPrivateMessageRespVO>> pullPrivateMessageList(@RequestParam("minId") Long minId, | ||
| 45 | - @RequestParam("size") Integer size) { | 45 | + public CommonResult<List<ImPrivateMessageRespVO>> pullPrivateMessageList( |
| 46 | + @RequestParam("minId") Long minId, | ||
| 47 | + @RequestParam("size") @Min(value = 1, message = "拉取数量最小值为 1") Integer size) { | ||
| 46 | List<ImPrivateMessageDO> messages = privateMessageService.pullPrivateMessageList(getLoginUserId(), minId, size); | 48 | List<ImPrivateMessageDO> messages = privateMessageService.pullPrivateMessageList(getLoginUserId(), minId, size); |
| 47 | return success(BeanUtils.toBean(messages, ImPrivateMessageRespVO.class)); | 49 | return success(BeanUtils.toBean(messages, ImPrivateMessageRespVO.class)); |
| 48 | } | 50 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFacePackItemMapper.java
| @@ -20,7 +20,7 @@ public interface ImFacePackItemMapper extends BaseMapperX<ImFacePackItemDO> { | @@ -20,7 +20,7 @@ public interface ImFacePackItemMapper extends BaseMapperX<ImFacePackItemDO> { | ||
| 20 | 20 | ||
| 21 | default List<ImFacePackItemDO> selectListByPackIdsAndStatus(Collection<Long> packIds, Integer status) { | 21 | default List<ImFacePackItemDO> selectListByPackIdsAndStatus(Collection<Long> packIds, Integer status) { |
| 22 | return selectList(new LambdaQueryWrapperX<ImFacePackItemDO>() | 22 | return selectList(new LambdaQueryWrapperX<ImFacePackItemDO>() |
| 23 | - .inIfPresent(ImFacePackItemDO::getPackId, packIds) | 23 | + .in(ImFacePackItemDO::getPackId, packIds) |
| 24 | .eq(ImFacePackItemDO::getStatus, status) | 24 | .eq(ImFacePackItemDO::getStatus, status) |
| 25 | .orderByAsc(ImFacePackItemDO::getPackId) | 25 | .orderByAsc(ImFacePackItemDO::getPackId) |
| 26 | .orderByAsc(ImFacePackItemDO::getSort) | 26 | .orderByAsc(ImFacePackItemDO::getSort) |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/statistics/ImStatisticsManagerMapper.java
| @@ -73,7 +73,7 @@ public interface ImStatisticsManagerMapper { | @@ -73,7 +73,7 @@ public interface ImStatisticsManagerMapper { | ||
| 73 | // ==================== 群 ==================== | 73 | // ==================== 群 ==================== |
| 74 | 74 | ||
| 75 | /** | 75 | /** |
| 76 | - * 群总数(im_group) | 76 | + * 当前有效群总数 |
| 77 | */ | 77 | */ |
| 78 | @Select("SELECT COUNT(*) FROM im_group WHERE deleted = 0 AND status = 0") | 78 | @Select("SELECT COUNT(*) FROM im_group WHERE deleted = 0 AND status = 0") |
| 79 | Long selectTotalGroupCount(); | 79 | Long selectTotalGroupCount(); |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/core/LiveKitClient.java
| @@ -90,7 +90,7 @@ public class LiveKitClient { | @@ -90,7 +90,7 @@ public class LiveKitClient { | ||
| 90 | .setNotBefore(new Date(nowSec * 1000)) | 90 | .setNotBefore(new Date(nowSec * 1000)) |
| 91 | .setExpiresAt(new Date((nowSec + ttlSec) * 1000)) | 91 | .setExpiresAt(new Date((nowSec + ttlSec) * 1000)) |
| 92 | .setPayload("video", video) | 92 | .setPayload("video", video) |
| 93 | - .setSigner(JWTSignerUtil.hs256(cfg.getApiSecret().getBytes())); | 93 | + .setSigner(JWTSignerUtil.hs256(cfg.getApiSecret().getBytes(StandardCharsets.UTF_8))); |
| 94 | if (StrUtil.isNotEmpty(displayName)) { | 94 | if (StrUtil.isNotEmpty(displayName)) { |
| 95 | jwt.setPayload("name", displayName); | 95 | jwt.setPayload("name", displayName); |
| 96 | } | 96 | } |
| @@ -219,7 +219,7 @@ public class LiveKitClient { | @@ -219,7 +219,7 @@ public class LiveKitClient { | ||
| 219 | .setNotBefore(new Date(nowSec * 1000)) | 219 | .setNotBefore(new Date(nowSec * 1000)) |
| 220 | .setExpiresAt(new Date((nowSec + ADMIN_TOKEN_TTL.getSeconds()) * 1000)) | 220 | .setExpiresAt(new Date((nowSec + ADMIN_TOKEN_TTL.getSeconds()) * 1000)) |
| 221 | .setPayload("video", MapUtil.of("roomAdmin", true)) | 221 | .setPayload("video", MapUtil.of("roomAdmin", true)) |
| 222 | - .setSigner(JWTSignerUtil.hs256(cfg.getApiSecret().getBytes())) | 222 | + .setSigner(JWTSignerUtil.hs256(cfg.getApiSecret().getBytes(StandardCharsets.UTF_8))) |
| 223 | .sign(); | 223 | .sign(); |
| 224 | } | 224 | } |
| 225 | 225 |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/web/package-info.java
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java
| 1 | package cn.iocoder.yudao.module.im.service.friend; | 1 | package cn.iocoder.yudao.module.im.service.friend; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.hutool.core.util.BooleanUtil; | 4 | import cn.hutool.core.util.BooleanUtil; |
| 4 | import cn.hutool.extra.spring.SpringUtil; | 5 | import cn.hutool.extra.spring.SpringUtil; |
| 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 6 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| @@ -28,6 +29,7 @@ import org.springframework.validation.annotation.Validated; | @@ -28,6 +29,7 @@ import org.springframework.validation.annotation.Validated; | ||
| 28 | 29 | ||
| 29 | import java.time.LocalDateTime; | 30 | import java.time.LocalDateTime; |
| 30 | import java.util.Collection; | 31 | import java.util.Collection; |
| 32 | +import java.util.Collections; | ||
| 31 | import java.util.List; | 33 | import java.util.List; |
| 32 | 34 | ||
| 33 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 35 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| @@ -100,6 +102,9 @@ public class ImFriendServiceImpl implements ImFriendService { | @@ -100,6 +102,9 @@ public class ImFriendServiceImpl implements ImFriendService { | ||
| 100 | 102 | ||
| 101 | @Override | 103 | @Override |
| 102 | public List<ImFriendDO> getActiveFriendList(Long userId, Collection<Long> friendUserIds) { | 104 | public List<ImFriendDO> getActiveFriendList(Long userId, Collection<Long> friendUserIds) { |
| 105 | + if (CollUtil.isEmpty(friendUserIds)) { | ||
| 106 | + return Collections.emptyList(); | ||
| 107 | + } | ||
| 103 | return friendMapper.selectListByUserIdAndFriendUserIdsAndStatus(userId, friendUserIds, | 108 | return friendMapper.selectListByUserIdAndFriendUserIdsAndStatus(userId, friendUserIds, |
| 104 | CommonStatusEnum.ENABLE.getStatus()); | 109 | CommonStatusEnum.ENABLE.getStatus()); |
| 105 | } | 110 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImpl.java
| @@ -669,6 +669,10 @@ public class ImGroupServiceImpl implements ImGroupService { | @@ -669,6 +669,10 @@ public class ImGroupServiceImpl implements ImGroupService { | ||
| 669 | * 三档分层禁言权限校验 | 669 | * 三档分层禁言权限校验 |
| 670 | */ | 670 | */ |
| 671 | private void validateMutePermission(ImGroupMemberDO operator, ImGroupMemberDO target) { | 671 | private void validateMutePermission(ImGroupMemberDO operator, ImGroupMemberDO target) { |
| 672 | + // 普通成员不能禁言任何人 | ||
| 673 | + if (!ImGroupMemberRoleEnum.isOwnerOrAdmin(operator.getRole())) { | ||
| 674 | + throw exception(GROUP_NOT_OWNER_OR_ADMIN); | ||
| 675 | + } | ||
| 672 | // 群主不可被禁言 | 676 | // 群主不可被禁言 |
| 673 | if (ImGroupMemberRoleEnum.isOwner(target.getRole())) { | 677 | if (ImGroupMemberRoleEnum.isOwner(target.getRole())) { |
| 674 | throw exception(GROUP_MUTE_OWNER_DENIED); | 678 | throw exception(GROUP_MUTE_OWNER_DENIED); |
| @@ -677,10 +681,6 @@ public class ImGroupServiceImpl implements ImGroupService { | @@ -677,10 +681,6 @@ public class ImGroupServiceImpl implements ImGroupService { | ||
| 677 | if (ImGroupMemberRoleEnum.isAdmin(target.getRole()) && !ImGroupMemberRoleEnum.isOwner(operator.getRole())) { | 681 | if (ImGroupMemberRoleEnum.isAdmin(target.getRole()) && !ImGroupMemberRoleEnum.isOwner(operator.getRole())) { |
| 678 | throw exception(GROUP_MUTE_ADMIN_DENIED); | 682 | throw exception(GROUP_MUTE_ADMIN_DENIED); |
| 679 | } | 683 | } |
| 680 | - // 普通成员不能禁言任何人 | ||
| 681 | - if (!ImGroupMemberRoleEnum.isOwnerOrAdmin(operator.getRole())) { | ||
| 682 | - throw exception(GROUP_NOT_OWNER_OR_ADMIN); | ||
| 683 | - } | ||
| 684 | } | 684 | } |
| 685 | 685 | ||
| 686 | private ImGroupServiceImpl getSelf() { | 686 | private ImGroupServiceImpl getSelf() { |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerServiceImpl.java
| @@ -71,7 +71,7 @@ public class ImStatisticsManagerServiceImpl implements ImStatisticsManagerServic | @@ -71,7 +71,7 @@ public class ImStatisticsManagerServiceImpl implements ImStatisticsManagerServic | ||
| 71 | List<Map<String, Object>> rows = statisticsMapper.selectGroupSizeDistribution(); | 71 | List<Map<String, Object>> rows = statisticsMapper.selectGroupSizeDistribution(); |
| 72 | return convertMap(rows, | 72 | return convertMap(rows, |
| 73 | row -> (String) row.get("range"), | 73 | row -> (String) row.get("range"), |
| 74 | - row -> (Long) row.get("count")); | 74 | + row -> Convert.toLong(row.get("count"))); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | // ==================== 消息 ==================== | 77 | // ==================== 消息 ==================== |
| @@ -102,16 +102,16 @@ public class ImStatisticsManagerServiceImpl implements ImStatisticsManagerServic | @@ -102,16 +102,16 @@ public class ImStatisticsManagerServiceImpl implements ImStatisticsManagerServic | ||
| 102 | public Map<Integer, Long> getMessageTypeCountMap(LocalDateTime beginTime, LocalDateTime endTime) { | 102 | public Map<Integer, Long> getMessageTypeCountMap(LocalDateTime beginTime, LocalDateTime endTime) { |
| 103 | List<Map<String, Object>> rows = statisticsMapper.selectMessageTypeDistribution(beginTime, endTime); | 103 | List<Map<String, Object>> rows = statisticsMapper.selectMessageTypeDistribution(beginTime, endTime); |
| 104 | return convertMap(rows, | 104 | return convertMap(rows, |
| 105 | - row -> (Integer) row.get("type"), | ||
| 106 | - row -> (Long) row.get("count")); | 105 | + row -> Convert.toInt(row.get("type")), |
| 106 | + row -> Convert.toLong(row.get("count"))); | ||
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | @Override | 109 | @Override |
| 110 | public Map<Long, Long> getTopSenderCountMap(LocalDateTime beginTime, LocalDateTime endTime, int limit) { | 110 | public Map<Long, Long> getTopSenderCountMap(LocalDateTime beginTime, LocalDateTime endTime, int limit) { |
| 111 | List<Map<String, Object>> rows = statisticsMapper.selectTopSenders(beginTime, endTime, limit); | 111 | List<Map<String, Object>> rows = statisticsMapper.selectTopSenders(beginTime, endTime, limit); |
| 112 | return convertMap(rows, | 112 | return convertMap(rows, |
| 113 | - row -> (Long) row.get("userId"), | ||
| 114 | - row -> (Long) row.get("messageCount")); | 113 | + row -> Convert.toLong(row.get("userId")), |
| 114 | + row -> Convert.toLong(row.get("messageCount"))); | ||
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | /** | 117 | /** |
| @@ -120,7 +120,7 @@ public class ImStatisticsManagerServiceImpl implements ImStatisticsManagerServic | @@ -120,7 +120,7 @@ public class ImStatisticsManagerServiceImpl implements ImStatisticsManagerServic | ||
| 120 | private static Map<LocalDateTime, Long> toDailyCountMap(List<Map<String, Object>> rows) { | 120 | private static Map<LocalDateTime, Long> toDailyCountMap(List<Map<String, Object>> rows) { |
| 121 | return convertMap(rows, | 121 | return convertMap(rows, |
| 122 | row -> Convert.convert(LocalDate.class, row.get("date")).atStartOfDay(), | 122 | row -> Convert.convert(LocalDate.class, row.get("date")).atStartOfDay(), |
| 123 | - row -> (Long) row.get("count")); | 123 | + row -> Convert.toLong(row.get("count"))); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | } | 126 | } |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImplTest.java
| @@ -17,6 +17,7 @@ import org.mockito.Mock; | @@ -17,6 +17,7 @@ import org.mockito.Mock; | ||
| 17 | import org.springframework.dao.DuplicateKeyException; | 17 | import org.springframework.dao.DuplicateKeyException; |
| 18 | 18 | ||
| 19 | import java.time.LocalDateTime; | 19 | import java.time.LocalDateTime; |
| 20 | +import java.util.Collections; | ||
| 20 | import java.util.List; | 21 | import java.util.List; |
| 21 | 22 | ||
| 22 | import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FRIEND_NOT_FRIEND; | 23 | import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FRIEND_NOT_FRIEND; |
| @@ -213,4 +214,12 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | @@ -213,4 +214,12 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | ||
| 213 | assertEquals(2, result.size()); | 214 | assertEquals(2, result.size()); |
| 214 | } | 215 | } |
| 215 | 216 | ||
| 217 | + @Test | ||
| 218 | + public void testGetActiveFriendList_emptySkip() { | ||
| 219 | + List<ImFriendDO> result = friendService.getActiveFriendList(1L, Collections.emptyList()); | ||
| 220 | + | ||
| 221 | + assertTrue(result.isEmpty()); | ||
| 222 | + verify(imFriendMapper, never()).selectListByUserIdAndFriendUserIdsAndStatus(anyLong(), anyCollection(), anyInt()); | ||
| 223 | + } | ||
| 224 | + | ||
| 216 | } | 225 | } |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImplTest.java
| @@ -7,10 +7,12 @@ import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | @@ -7,10 +7,12 @@ import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | ||
| 7 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupAdminAddReqVO; | 7 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupAdminAddReqVO; |
| 8 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupAdminRemoveReqVO; | 8 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupAdminRemoveReqVO; |
| 9 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupCreateReqVO; | 9 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupCreateReqVO; |
| 10 | +import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupMuteMemberReqVO; | ||
| 10 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupTransferOwnerReqVO; | 11 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupTransferOwnerReqVO; |
| 11 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupUpdateReqVO; | 12 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupUpdateReqVO; |
| 12 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberInviteReqVO; | 13 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberInviteReqVO; |
| 13 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberRemoveReqVO; | 14 | import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberRemoveReqVO; |
| 15 | +import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupManagerBanReqVO; | ||
| 14 | import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO; | 16 | import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO; |
| 15 | import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO; | 17 | import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO; |
| 16 | import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO; | 18 | import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO; |
| @@ -932,6 +934,76 @@ public class ImGroupServiceImplTest extends BaseMockitoUnitTest { | @@ -932,6 +934,76 @@ public class ImGroupServiceImplTest extends BaseMockitoUnitTest { | ||
| 932 | } | 934 | } |
| 933 | } | 935 | } |
| 934 | 936 | ||
| 937 | + // ========== banGroup ========== | ||
| 938 | + | ||
| 939 | + @Test | ||
| 940 | + public void testBanGroup_dissolved() { | ||
| 941 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | ||
| 942 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class))) | ||
| 943 | + .thenReturn(groupService); | ||
| 944 | + | ||
| 945 | + ImGroupDO group = ImGroupDO.builder().id(10L).status(CommonStatusEnum.DISABLE.getStatus()).build(); | ||
| 946 | + when(groupMapper.selectById(10L)).thenReturn(group); | ||
| 947 | + | ||
| 948 | + ImGroupManagerBanReqVO reqVO = new ImGroupManagerBanReqVO(); | ||
| 949 | + reqVO.setId(10L).setReason("违规"); | ||
| 950 | + | ||
| 951 | + ServiceException exception = assertThrows(ServiceException.class, | ||
| 952 | + () -> groupService.banGroup(1L, reqVO)); | ||
| 953 | + assertEquals(GROUP_DISSOLVED.getCode(), exception.getCode()); | ||
| 954 | + verify(groupMapper, never()).updateById(any(ImGroupDO.class)); | ||
| 955 | + verify(groupMessageService, never()).sendGroupMessage(anyLong(), any(ImGroupMessageSendDTO.class)); | ||
| 956 | + } | ||
| 957 | + } | ||
| 958 | + | ||
| 959 | + @Test | ||
| 960 | + public void testBanGroup_alreadyBannedSkip() { | ||
| 961 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | ||
| 962 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class))) | ||
| 963 | + .thenReturn(groupService); | ||
| 964 | + | ||
| 965 | + ImGroupDO group = ImGroupDO.builder().id(10L).banned(true) | ||
| 966 | + .status(CommonStatusEnum.ENABLE.getStatus()).build(); | ||
| 967 | + when(groupMapper.selectById(10L)).thenReturn(group); | ||
| 968 | + | ||
| 969 | + ImGroupManagerBanReqVO reqVO = new ImGroupManagerBanReqVO(); | ||
| 970 | + reqVO.setId(10L).setReason("违规"); | ||
| 971 | + | ||
| 972 | + groupService.banGroup(1L, reqVO); | ||
| 973 | + | ||
| 974 | + verify(groupMapper, never()).updateById(any(ImGroupDO.class)); | ||
| 975 | + verify(groupMessageService, never()).sendGroupMessage(anyLong(), any(ImGroupMessageSendDTO.class)); | ||
| 976 | + } | ||
| 977 | + } | ||
| 978 | + | ||
| 979 | + // ========== muteMember ========== | ||
| 980 | + | ||
| 981 | + @Test | ||
| 982 | + public void testMuteMember_normalCannotMuteAdmin() { | ||
| 983 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | ||
| 984 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class))) | ||
| 985 | + .thenReturn(groupService); | ||
| 986 | + | ||
| 987 | + ImGroupDO group = ImGroupDO.builder().id(10L).status(CommonStatusEnum.ENABLE.getStatus()).build(); | ||
| 988 | + when(groupMapper.selectById(10L)).thenReturn(group); | ||
| 989 | + when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn( | ||
| 990 | + ImGroupMemberDO.builder().groupId(10L).userId(1L) | ||
| 991 | + .role(ImGroupMemberRoleEnum.NORMAL.getRole()).build()); | ||
| 992 | + when(groupMemberService.validateMemberInGroup(10L, 2L)).thenReturn( | ||
| 993 | + ImGroupMemberDO.builder().groupId(10L).userId(2L) | ||
| 994 | + .role(ImGroupMemberRoleEnum.ADMIN.getRole()).build()); | ||
| 995 | + | ||
| 996 | + ImGroupMuteMemberReqVO reqVO = new ImGroupMuteMemberReqVO(); | ||
| 997 | + reqVO.setGroupId(10L).setUserId(2L).setMutedSeconds(60); | ||
| 998 | + | ||
| 999 | + ServiceException exception = assertThrows(ServiceException.class, | ||
| 1000 | + () -> groupService.muteMember(1L, reqVO)); | ||
| 1001 | + assertEquals(GROUP_NOT_OWNER_OR_ADMIN.getCode(), exception.getCode()); | ||
| 1002 | + verify(groupMemberService, never()).updateGroupMemberMuteEndTime(anyLong(), anyLong(), any()); | ||
| 1003 | + verify(groupMessageService, never()).sendGroupMessage(anyLong(), any(ImGroupMessageSendDTO.class)); | ||
| 1004 | + } | ||
| 1005 | + } | ||
| 1006 | + | ||
| 935 | // ========== validateGroupExists ========== | 1007 | // ========== validateGroupExists ========== |
| 936 | 1008 | ||
| 937 | @Test | 1009 | @Test |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerServiceImplTest.java
| @@ -6,6 +6,7 @@ import org.junit.jupiter.api.Test; | @@ -6,6 +6,7 @@ import org.junit.jupiter.api.Test; | ||
| 6 | import org.mockito.InjectMocks; | 6 | import org.mockito.InjectMocks; |
| 7 | import org.mockito.Mock; | 7 | import org.mockito.Mock; |
| 8 | 8 | ||
| 9 | +import java.math.BigInteger; | ||
| 9 | import java.time.LocalDate; | 10 | import java.time.LocalDate; |
| 10 | import java.time.LocalDateTime; | 11 | import java.time.LocalDateTime; |
| 11 | import java.util.Arrays; | 12 | import java.util.Arrays; |
| @@ -75,10 +76,10 @@ public class ImStatisticsManagerServiceImplTest extends BaseMockitoUnitTest { | @@ -75,10 +76,10 @@ public class ImStatisticsManagerServiceImplTest extends BaseMockitoUnitTest { | ||
| 75 | 76 | ||
| 76 | @Test | 77 | @Test |
| 77 | public void testGetNewUserDailyCountMap_dateConvert() { | 78 | public void testGetNewUserDailyCountMap_dateConvert() { |
| 78 | - // 准备:date 字段以 SQL Date / String 混入,count 为 Long | 79 | + // 准备:date 字段以 SQL Date / String 混入,count 混入多种 Number |
| 79 | when(statisticsMapper.selectNewUserDailyCount(eq(BEGIN), eq(END))).thenReturn(Arrays.asList( | 80 | when(statisticsMapper.selectNewUserDailyCount(eq(BEGIN), eq(END))).thenReturn(Arrays.asList( |
| 80 | - row("date", java.sql.Date.valueOf("2026-01-10"), "count", 5L), | ||
| 81 | - row("date", "2026-01-11", "count", 8L))); | 81 | + row("date", java.sql.Date.valueOf("2026-01-10"), "count", BigInteger.valueOf(5)), |
| 82 | + row("date", "2026-01-11", "count", 8))); | ||
| 82 | 83 | ||
| 83 | // 调用 | 84 | // 调用 |
| 84 | Map<LocalDateTime, Long> result = service.getNewUserDailyCountMap(BEGIN, END); | 85 | Map<LocalDateTime, Long> result = service.getNewUserDailyCountMap(BEGIN, END); |
| @@ -119,8 +120,8 @@ public class ImStatisticsManagerServiceImplTest extends BaseMockitoUnitTest { | @@ -119,8 +120,8 @@ public class ImStatisticsManagerServiceImplTest extends BaseMockitoUnitTest { | ||
| 119 | @Test | 120 | @Test |
| 120 | public void testGetGroupSizeCountMap() { | 121 | public void testGetGroupSizeCountMap() { |
| 121 | when(statisticsMapper.selectGroupSizeDistribution()).thenReturn(Arrays.asList( | 122 | when(statisticsMapper.selectGroupSizeDistribution()).thenReturn(Arrays.asList( |
| 122 | - row("range", "1-9 人", "count", 3L), | ||
| 123 | - row("range", "10-49 人", "count", 2L))); | 123 | + row("range", "1-9 人", "count", BigInteger.valueOf(3)), |
| 124 | + row("range", "10-49 人", "count", 2))); | ||
| 124 | 125 | ||
| 125 | Map<String, Long> result = service.getGroupSizeCountMap(); | 126 | Map<String, Long> result = service.getGroupSizeCountMap(); |
| 126 | assertEquals(3L, result.get("1-9 人")); | 127 | assertEquals(3L, result.get("1-9 人")); |
| @@ -130,8 +131,8 @@ public class ImStatisticsManagerServiceImplTest extends BaseMockitoUnitTest { | @@ -130,8 +131,8 @@ public class ImStatisticsManagerServiceImplTest extends BaseMockitoUnitTest { | ||
| 130 | @Test | 131 | @Test |
| 131 | public void testGetMessageTypeCountMap() { | 132 | public void testGetMessageTypeCountMap() { |
| 132 | when(statisticsMapper.selectMessageTypeDistribution(BEGIN, END)).thenReturn(Arrays.asList( | 133 | when(statisticsMapper.selectMessageTypeDistribution(BEGIN, END)).thenReturn(Arrays.asList( |
| 133 | - row("type", 101, "count", 8L), | ||
| 134 | - row("type", 102, "count", 1L))); | 134 | + row("type", 101L, "count", BigInteger.valueOf(8)), |
| 135 | + row("type", 102, "count", 1))); | ||
| 135 | 136 | ||
| 136 | Map<Integer, Long> result = service.getMessageTypeCountMap(BEGIN, END); | 137 | Map<Integer, Long> result = service.getMessageTypeCountMap(BEGIN, END); |
| 137 | assertEquals(8L, result.get(101)); | 138 | assertEquals(8L, result.get(101)); |
| @@ -141,8 +142,8 @@ public class ImStatisticsManagerServiceImplTest extends BaseMockitoUnitTest { | @@ -141,8 +142,8 @@ public class ImStatisticsManagerServiceImplTest extends BaseMockitoUnitTest { | ||
| 141 | @Test | 142 | @Test |
| 142 | public void testGetTopSenderCountMap_passesLimit() { | 143 | public void testGetTopSenderCountMap_passesLimit() { |
| 143 | when(statisticsMapper.selectTopSenders(BEGIN, END, 3)).thenReturn(Arrays.asList( | 144 | when(statisticsMapper.selectTopSenders(BEGIN, END, 3)).thenReturn(Arrays.asList( |
| 144 | - row("userId", 1L, "messageCount", 10L), | ||
| 145 | - row("userId", 2L, "messageCount", 5L))); | 145 | + row("userId", 1, "messageCount", BigInteger.valueOf(10)), |
| 146 | + row("userId", 2L, "messageCount", 5))); | ||
| 146 | 147 | ||
| 147 | Map<Long, Long> result = service.getTopSenderCountMap(BEGIN, END, 3); | 148 | Map<Long, Long> result = service.getTopSenderCountMap(BEGIN, END, 3); |
| 148 | assertEquals(10L, result.get(1L)); | 149 | assertEquals(10L, result.get(1L)); |