Commit 4092f298ed15b4e3256c698068c41d50d6f2333f

Authored by zhijiantianya@gmail.com
1 parent 68c9d563

code review:crm 权限模块的实现

Showing 18 changed files with 67 additions and 18 deletions
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessTransferReqVO.java
... ... @@ -21,6 +21,7 @@ public class CrmBusinessTransferReqVO {
21 21 @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430")
22 22 private Long newOwnerUserId;
23 23  
  24 + // TODO @puhui999:joinTeam 可以合并成 permissionLevel 里;oldOwnerPermissionLevel;这样 null 说明移除,因为都换负责人啦;
24 25 /**
25 26 * 老负责人是否加入团队,是/否
26 27 */
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactTransferReqVO.java
... ... @@ -21,13 +21,13 @@ public class CrmContactTransferReqVO {
21 21 @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430")
22 22 private Long newOwnerUserId;
23 23  
  24 + // TODO @puhui999:joinTeam 可以合并成 permissionLevel 里;oldOwnerPermissionLevel;这样 null 说明移除,因为都换负责人啦;
24 25 /**
25 26 * 老负责人是否加入团队,是/否
26 27 */
27 28 @Schema(description = "老负责人是否加入团队", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
28 29 @NotNull(message = "老负责人是否加入团队不能为空")
29 30 private Boolean joinTeam;
30   -
31 31 /**
32 32 * 老负责人加入团队后的权限级别。如果 {@link #joinTeam} 为 false, permissionLevel 为 null
33 33 * 关联 {@link CrmPermissionLevelEnum}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractTransferReqVO.java
... ... @@ -21,6 +21,7 @@ public class CrmContractTransferReqVO {
21 21 @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430")
22 22 private Long newOwnerUserId;
23 23  
  24 + // TODO @puhui999:joinTeam 可以合并成 permissionLevel 里;oldOwnerPermissionLevel;这样 null 说明移除,因为都换负责人啦;
24 25 /**
25 26 * 老负责人是否加入团队,是/否
26 27 */
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerTransferReqVO.java
... ... @@ -21,6 +21,7 @@ public class CrmCustomerTransferReqVO {
21 21 @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430")
22 22 private Long newOwnerUserId;
23 23  
  24 + // TODO @puhui999:joinTeam 可以合并成 permissionLevel 里;oldOwnerPermissionLevel;这样 null 说明移除,因为都换负责人啦;
24 25 /**
25 26 * 老负责人是否加入团队,是/否
26 27 */
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java
... ... @@ -48,9 +48,11 @@ public class CrmPermissionController {
48 48 @Resource
49 49 private List<CrmPermissionValidateService> permissionValidateServices;
50 50  
  51 + // TODO @puhui999:这个能不能使用 CrmPermission 注解替代?
51 52 private void validatePermission(Integer bizType, Long bizId) {
52 53 // 1. TODO 校验是否为超级管理员
53 54 // 2. 防御一手,如果是超级管理员不校验权限还是得校验一下数据是否存在
  55 + // TODO @puhui999:是不是不用校验每个业务方的数据是否存在;其实不是很关键哈;简单一点~ 说白了,负责人只要在,它的数据就是存在~
54 56 permissionValidateServices.forEach(item -> {
55 57 if (!item.validateBizIdExists(bizType, bizId)) {
56 58 throw exception(CRM_PERMISSION_MODEL_NOT_EXISTS, getNameByType(bizType));
... ... @@ -90,9 +92,11 @@ public class CrmPermissionController {
90 92 return success(true);
91 93 }
92 94  
  95 + // TODO @puhui999:deletemapping
93 96 @GetMapping("/delete")
94 97 @Operation(summary = "移除团队成员")
95 98 @Parameter(name = "id", description = "团队成员编号", required = true)
  99 + // TODO @puhui999:是不是 id 参数就够了?
96 100 @PreAuthorize("@ss.hasPermission('crm:permission:delete')")
97 101 public CommonResult<Boolean> deletePermission(@RequestParam("bizType") Integer bizType,
98 102 @RequestParam("bizId") Long bizId,
... ... @@ -105,6 +109,8 @@ public class CrmPermissionController {
105 109 return success(true);
106 110 }
107 111  
  112 + // TODO @puhui999:这个是哪个地方使用到哈?
  113 + // TODO @puhui999:是不是 deletemapping 呀;
108 114 @GetMapping("/quit")
109 115 @Operation(summary = "退出团队")
110 116 @Parameters({
... ... @@ -114,9 +120,10 @@ public class CrmPermissionController {
114 120 @PreAuthorize("@ss.hasPermission('crm:permission:delete')")
115 121 public CommonResult<Boolean> quitPermission(@RequestParam("bizType") Integer bizType,
116 122 @RequestParam("bizId") Long bizId) {
  123 + // 没有就不是团队成员
117 124 CrmPermissionDO permission = crmPermissionService.getPermissionByBizTypeAndBizIdAndUserId(
118 125 bizType, bizId, getLoginUserId());
119   - if (permission == null) { // 没有就不是团队成员
  126 + if (permission == null) {
120 127 return success(false);
121 128 }
122 129 crmPermissionService.deletePermission(permission.getId());
... ... @@ -136,6 +143,7 @@ public class CrmPermissionController {
136 143 if (CollUtil.isEmpty(permission)) {
137 144 return success(Collections.emptyList());
138 145 }
  146 + // TODO @puhui999:池子的逻辑;
139 147 permission.removeIf(item -> ObjUtil.equal(item.getUserId(), CrmPermissionDO.POOL_USER_ID)); // 排除
140 148  
141 149 // 拼接数据
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionBaseVO.java
... ... @@ -30,6 +30,7 @@ public class CrmPermissionBaseVO {
30 30 @NotNull(message = "Crm 类型数据编号不能为空")
31 31 private Long bizId;
32 32  
  33 + // TODO @puhui999:level;
33 34 @Schema(description = "权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
34 35 @InEnum(CrmPermissionLevelEnum.class)
35 36 @NotNull(message = "权限级别不能为空")
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionRespVO.java
... ... @@ -12,9 +12,11 @@ public class CrmPermissionRespVO extends CrmPermissionBaseVO {
12 12 @Schema(description = "数据权限编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
13 13 private Long id;
14 14  
  15 + // TODO @puhui999:搞到字典里;
15 16 @Schema(description = "团队级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "负责人")
16 17 private String permissionLevelName;
17 18  
  19 + // TODO @puhui999:deptId、postIds 是不是要提供中文名哈;
18 20 @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
19 21 private Long deptId;
20 22  
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionUpdateReqVO.java
... ... @@ -12,6 +12,9 @@ import lombok.ToString;
12 12 public class CrmPermissionUpdateReqVO extends CrmPermissionBaseVO {
13 13  
14 14 @Schema(description = "数据权限编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
  15 + // TODO @puhui999:非空判断;
15 16 private Long id;
16 17  
  18 + // TODO @puhui999:是不是只更新 permission???
  19 +
17 20 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/permission/CrmPermissionDO.java
... ... @@ -23,6 +23,7 @@ import lombok.*;
23 23 @AllArgsConstructor
24 24 public class CrmPermissionDO extends BaseDO {
25 25  
  26 + // TODO puhui999:是不是公海的数据,就不插入了;
26 27 /**
27 28 * 当数据变为公海数据时,也就是数据团队成员中没有负责人的时候,将原本的负责人 userId 设置为 POOL_USER_ID 方便查询公海数据。
28 29 * 也就是说每条数据到最后都有一个负责人,如果有人领取则 userId 为领取人
... ... @@ -34,22 +35,35 @@ public class CrmPermissionDO extends BaseDO {
34 35 */
35 36 @TableId
36 37 private Long id;
  38 +
37 39 /**
38   - * 数据类型,关联 {@link CrmBizTypeEnum}
  40 + * 数据类型
  41 + *
  42 + * 枚举 {@link CrmBizTypeEnum}
39 43 */
40 44 private Integer bizType;
41 45 /**
42   - * 数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId()
  46 + * 数据编号
  47 + *
  48 + * 关联 {@link CrmBizTypeEnum} 对应模块 DO 的 id 字段
43 49 */
44 50 private Long bizId;
  51 +
45 52 /**
46   - * 团队成员,关联 AdminUser#id
  53 + * 团队成员
  54 + *
  55 + * 关联 AdminUser 的 id 字段
  56 + *
47 57 * 如果为公海数据的话会干掉此数据的负责人后设置为 {@link #POOL_USER_ID},领取人则上位负责人
48 58 * 例:客户放入公海后会干掉团队成员中的负责人,而其他团队成员则不受影响
49 59 */
50 60 private Long userId;
  61 +
  62 + // TODO @puhui999:是不是搞成 level 字段;简洁一点,主要表明已经 perssmion 实体里了;
51 63 /**
52   - * 权限级别,关联 {@link CrmPermissionLevelEnum}
  64 + * 权限级别
  65 + *
  66 + * 关联 {@link CrmPermissionLevelEnum}
53 67 */
54 68 private Integer permissionLevel;
55 69  
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmPermissionMapper.java
... ... @@ -18,6 +18,7 @@ import java.util.List;
18 18 @Mapper
19 19 public interface CrmPermissionMapper extends BaseMapperX<CrmPermissionDO> {
20 20  
  21 + // TODO @puhui999:是不是不用谢这个注释;因为方法名,可以自解释;
21 22 /**
22 23 * 获取用户数据权限通过 数据类型 x 某个数据 x 用户编号
23 24 *
... ... @@ -33,6 +34,7 @@ public interface CrmPermissionMapper extends BaseMapperX&lt;CrmPermissionDO&gt; {
33 34 .eq(CrmPermissionDO::getUserId, userId));
34 35 }
35 36  
  37 + // TODO @puhui999:是不是不用谢这个注释;因为方法名,可以自解释;
36 38 /**
37 39 * 获取数据权限列表通过 数据类型 x 某个数据
38 40 *
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/annotations/CrmPermission.java
... ... @@ -26,12 +26,14 @@ public @interface CrmPermission {
26 26 */
27 27 CrmBizTypeEnum bizType();
28 28  
  29 + // TODO @puhui999:id,通过 spring el 表达式获取;
29 30 /**
30 31 * 数据编号获取来源类,确保数据 id 编号在此类中,不能在父类中。
31 32 * 例:如果在 baseVO 中需要把 id 弄到 updateVO 中。
32 33 */
33 34 Class<?>[] getIdFor() default {};
34 35  
  36 + // TODO @puhui999:是不是搞成 level 字段;简洁一点,主要表明已经 perssmion 实体里了;
35 37 /**
36 38 * 操作类型
37 39 */
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/aop/CrmPermissionAspect.java
... ... @@ -43,6 +43,7 @@ public class CrmPermissionAspect {
43 43 return WebFrameworkUtils.getLoginUserId();
44 44 }
45 45  
  46 + // TODO @puhui999:id,通过 spring el 表达式获取;
46 47 private Long getBizId(JoinPoint joinPoint, CrmPermission crmPermission) throws NoSuchFieldException, IllegalAccessException {
47 48 Object[] args = joinPoint.getArgs();
48 49 for (Object arg : args) {
... ... @@ -61,6 +62,7 @@ public class CrmPermissionAspect {
61 62 return null;
62 63 }
63 64  
  65 + // TODO @puhui999:一般核心的方法,放到最前面,private 放后面。主要是,主次要分出来哈;
64 66 @Before("@annotation(crmPermission)")
65 67 public void doBefore(JoinPoint joinPoint, CrmPermission crmPermission) {
66 68 try {
... ... @@ -75,12 +77,17 @@ public class CrmPermissionAspect {
75 77  
76 78 // 1. 获取数据权限
77 79 List<CrmPermissionDO> bizPermissions = crmPermissionService.getPermissionByBizTypeAndBizId(bizType, bizId);
  80 + // TODO puhui999:这种情况下,最好是 CrmPermissionLevelEnum.isOwner
  81 + // 2.1 情况一:如果自己是负责人,则默认有所有权限
  82 + // TODO @puhui999:会不会存在空指针的问题?
78 83 CrmPermissionDO userPermission = CollUtil.findOne(bizPermissions, item -> ObjUtil.equal(item.getUserId(), getUserId()));
79   - if (isOwner(userPermission.getPermissionLevel())) { // 校验自己是否是负责人
  84 + if (isOwner(userPermission.getPermissionLevel())) {
80 85 return;
81 86 }
82   - if (isRead(permissionLevel)) { // 读权限
  87 + // 2.2 情况二:校验自己是否有读权限
  88 + if (isRead(permissionLevel)) {
83 89 // 如果没有数据权限或没有负责人则表示此记录为公海数据所有人都有只读权限可以领取成为负责人(团队成员领取的)
  90 + // TODO @puhui999:89 到 92 这块的逻辑,感觉可以不用 @CrmPermission,公海那自己 check 即可;
84 91 if (CollUtil.isEmpty(bizPermissions) || CollUtil.anyMatch(bizPermissions,
85 92 item -> ObjUtil.equal(item.getUserId(), CrmPermissionDO.POOL_USER_ID))) { // 详见 CrmPermissionDO.POOL_USER_ID 注释
86 93 return;
... ... @@ -88,20 +95,23 @@ public class CrmPermissionAspect {
88 95 if (isRead(userPermission.getPermissionLevel())) { // 校验当前用户是否有读权限
89 96 return;
90 97 }
91   - //如果查询数据的话拥有写权限的也能查询
  98 + // 如果查询数据的话拥有写权限的也能查询
92 99 if (isWrite(userPermission.getPermissionLevel())) { // 校验当前用户是否有写权限
93 100 return;
94 101 }
95 102 }
96   - if (isWrite(permissionLevel)) { // 写权限
  103 + // 2.3 情况三:校验自己是否有写权限
  104 + if (isWrite(permissionLevel)) {
97 105 if (isWrite(userPermission.getPermissionLevel())) { // 校验当前用户是否有写权限
98 106 return;
99 107 }
100 108 }
101 109  
102   - // 2. 没通过结束,报错 {}操作失败,原因:没有权限
  110 + // 3. 没通过结束,报错 {} 操作失败,原因:没有权限
  111 + // TODO @puhui999:这里打个 info 日志,方便后续排查问题、审计;
103 112 throw exception(CRM_PERMISSION_DENIED, crmPermission.bizType().getName());
104 113 } catch (Exception ex) {
  114 + // TODO @puhui999:不用 catch 掉,就是系统异常;
105 115 log.error("[doBefore][crmPermission({}) 数据校验错误]", toJsonString(crmPermission), ex);
106 116 // TODO 报错抛个什么异常好呢
107 117 throw exception(CRM_PERMISSION_DENIED, crmPermission.bizType().getName());
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/enums/CrmBizTypeEnum.java
... ... @@ -33,6 +33,7 @@ public enum CrmBizTypeEnum implements IntArrayValuable {
33 33 private final String name;
34 34  
35 35 public static String getNameByType(Integer type) {
  36 + // TODO @puhui999:可以 findone,更简洁;另外,不存在返回 null 即可啦;
36 37 for (CrmBizTypeEnum crmBizTypeEnum : CrmBizTypeEnum.values()) {
37 38 if (ObjUtil.equal(crmBizTypeEnum.type, type)) {
38 39 return crmBizTypeEnum.name;
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/enums/CrmPermissionLevelEnum.java
... ... @@ -19,6 +19,7 @@ public enum CrmPermissionLevelEnum implements IntArrayValuable {
19 19 OWNER(1, "负责人"),
20 20 READ(2, "读"),
21 21 WRITE(3, "写");
  22 +
22 23 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmPermissionLevelEnum::getLevel).toArray();
23 24  
24 25 /**
... ... @@ -48,6 +49,7 @@ public enum CrmPermissionLevelEnum implements IntArrayValuable {
48 49 }
49 50  
50 51 public static String getNameByLevel(Integer level) {
  52 + // TODO @puhui999:可以 findone,更简洁;另外,不存在返回 null 即可啦;
51 53 for (CrmPermissionLevelEnum levelEnum : CrmPermissionLevelEnum.values()) {
52 54 if (ObjUtil.equal(levelEnum.level, level)) {
53 55 return levelEnum.name;
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java
... ... @@ -55,6 +55,7 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
55 55 @Override
56 56 @Transactional(rollbackFor = Exception.class)
57 57 public void updatePermission(CrmPermissionUpdateReqBO updateBO) {
  58 + // TODO @puhui999:这里 1.1 1.2;下面 2.;这样更有序一点;
58 59 // 1. 校验用户是否存在
59 60 adminUserApi.validateUserList(Collections.singletonList(updateBO.getUserId()));
60 61 // 2. 校验存在
... ... @@ -91,7 +92,6 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
91 92 }
92 93 }
93 94  
94   -
95 95 @Override
96 96 public void transferPermission(CrmTransferPermissionReqBO transferReqBO) {
97 97 // 1. 校验数据权限-是否是负责人,只有负责人才可以转移
... ... @@ -103,6 +103,7 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
103 103 throw exception(CRM_PERMISSION_DENIED, crmName);
104 104 }
105 105  
  106 + // TODO @puhui999:这个顺序编号,看看调整下;2. 后面是 2.1 ,结果没 2.2 有点怪;
106 107 // 2. 校验转移对象是否已经是该负责人
107 108 if (ObjUtil.equal(transferReqBO.getNewOwnerUserId(), oldPermission.getUserId())) {
108 109 throw exception(CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS, crmName);
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionCreateReqBO.java
... ... @@ -27,16 +27,15 @@ public class CrmPermissionCreateReqBO {
27 27 @NotNull(message = "Crm 类型不能为空")
28 28 @InEnum(CrmBizTypeEnum.class)
29 29 private Integer bizType;
30   -
31 30 /**
32 31 * 数据编号
33 32 */
34 33 @NotNull(message = "Crm 数据编号不能为空")
35 34 private Long bizId;
36 35  
  36 + // TODO @puhui999:简化成 level
37 37 /**
38 38 * 权限级别
39   - * 关联 {@link CrmPermissionLevelEnum}
40 39 */
41 40 @NotNull(message = "权限级别不能为空")
42 41 @InEnum(CrmPermissionLevelEnum.class)
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionUpdateReqBO.java
... ... @@ -17,7 +17,7 @@ import javax.validation.constraints.NotNull;
17 17 public class CrmPermissionUpdateReqBO {
18 18  
19 19 /**
20   - * 数据权限编号 {@link CrmPermissionDO#getId()}
  20 + * 数据权限编号
21 21 */
22 22 @NotNull(message = "Crm 数据权限编号不能为空")
23 23 private Long id;
... ... @@ -28,22 +28,22 @@ public class CrmPermissionUpdateReqBO {
28 28 @NotNull(message = "用户编号不能为空")
29 29 private Long userId;
30 30  
  31 + // TODO @puhui999:id 字段,和 bizType + bizId 是否二选一;
31 32 /**
32 33 * Crm 类型
33 34 */
34 35 @NotNull(message = "Crm 类型不能为空")
35 36 @InEnum(CrmBizTypeEnum.class)
36 37 private Integer bizType;
37   -
38 38 /**
39 39 * 数据编号
40 40 */
41 41 @NotNull(message = "Crm 数据编号不能为空")
42 42 private Long bizId;
43 43  
  44 + // TODO @puhui999:简化成 level
44 45 /**
45 46 * 权限级别
46   - * 关联 {@link CrmPermissionLevelEnum}
47 47 */
48 48 @NotNull(message = "权限级别不能为空")
49 49 @InEnum(CrmPermissionLevelEnum.class)
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmTransferPermissionReqBO.java
... ... @@ -7,6 +7,7 @@ import lombok.Data;
7 7  
8 8 import javax.validation.constraints.NotNull;
9 9  
  10 +// TODO @puhui999:CrmPermissionTransferReqBO
10 11 /**
11 12 * 数据权限转移 Request BO
12 13 *
... ... @@ -27,7 +28,6 @@ public class CrmTransferPermissionReqBO {
27 28 @NotNull(message = "Crm 类型不能为空")
28 29 @InEnum(CrmBizTypeEnum.class)
29 30 private Integer bizType;
30   -
31 31 /**
32 32 * 数据编号
33 33 */
... ... @@ -40,6 +40,7 @@ public class CrmTransferPermissionReqBO {
40 40 @NotNull(message = "新负责人的用户编号不能为空")
41 41 private Long newOwnerUserId;
42 42  
  43 + // TODO @puhui999:joinTeam 可以合并成 permissionLevel 里;oldOwnerPermissionLevel;这样 null 说明移除,因为都换负责人啦;
43 44 /**
44 45 * 老负责人是否加入团队,是/否
45 46 */
... ...