Commit 8d94c7c1054e972bbfc9f3d12f871dbadbcc62df
1 parent
85f2928a
fix(crm): 校验转移后旧负责人保留权限级别
Showing
3 changed files
with
85 additions
and
3 deletions
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
| ... | ... | @@ -76,6 +76,7 @@ public interface ErrorCodeConstants { |
| 76 | 76 | ErrorCode CRM_PERMISSION_DELETE_SELF_PERMISSION_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_007, "删除数据权限失败,原因:不能删除负责人"); |
| 77 | 77 | ErrorCode CRM_PERMISSION_CREATE_FAIL = new ErrorCode(1_020_007_008, "创建数据权限失败,原因:所加用户已有权限"); |
| 78 | 78 | ErrorCode CRM_PERMISSION_CREATE_FAIL_EXISTS = new ErrorCode(1_020_007_009, "同时添加数据权限失败,原因:用户【{}】已有模块【{}】数据【{}】的【{}】权限"); |
| 79 | + ErrorCode CRM_PERMISSION_MODEL_TRANSFER_FAIL_OLD_OWNER_PERMISSION_LEVEL_ERROR = new ErrorCode(1_020_007_010, "{}操作失败,原因:老负责人的权限级别只能是只读或读写"); | |
| 79 | 80 | |
| 80 | 81 | // ========== 产品 1_020_008_000 ========== |
| 81 | 82 | ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_020_008_000, "产品不存在"); | ... | ... |
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java
| ... | ... | @@ -34,6 +34,8 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU |
| 34 | 34 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 35 | 35 | import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; |
| 36 | 36 | import static cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum.isOwner; |
| 37 | +import static cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum.isRead; | |
| 38 | +import static cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum.isWrite; | |
| 37 | 39 | |
| 38 | 40 | /** |
| 39 | 41 | * CRM 数据权限 Service 接口实现类 |
| ... | ... | @@ -216,17 +218,22 @@ public class CrmPermissionServiceImpl implements CrmPermissionService { |
| 216 | 218 | if (!owner && !CrmPermissionUtils.isCrmAdmin()) { |
| 217 | 219 | throw exception(CRM_PERMISSION_DENIED, bizTypeName); |
| 218 | 220 | } |
| 219 | - // 1.2 获得老负责人的权限:操作人是负责人时,就是操作人的权限;否则(CRM 管理员),是数据实际的负责人,而不是管理员自己的团队权限 | |
| 221 | + // 1.2 校验老负责人的权限级别:为空时表示移除,否则只能是只读或读写,避免出现多个负责人 | |
| 222 | + Integer oldOwnerPermissionLevel = transferReqBO.getOldOwnerPermissionLevel(); | |
| 223 | + if (oldOwnerPermissionLevel != null && !isRead(oldOwnerPermissionLevel) && !isWrite(oldOwnerPermissionLevel)) { | |
| 224 | + throw exception(CRM_PERMISSION_MODEL_TRANSFER_FAIL_OLD_OWNER_PERMISSION_LEVEL_ERROR, bizTypeName); | |
| 225 | + } | |
| 226 | + // 1.3 获得老负责人的权限:操作人是负责人时,就是操作人的权限;否则(CRM 管理员),是数据实际的负责人,而不是管理员自己的团队权限 | |
| 220 | 227 | CrmPermissionDO oldOwnerPermission = owner ? userPermission |
| 221 | 228 | : CollUtil.findOne(permissions, item -> isOwner(item.getLevel())); |
| 222 | 229 | if (oldOwnerPermission == null) { // 数据缺少负责人时,在修改任何权限前失败,避免部分写入 |
| 223 | 230 | throw exception(CRM_PERMISSION_NOT_EXISTS); |
| 224 | 231 | } |
| 225 | - // 1.3 校验转移对象是否已经是该负责人 | |
| 232 | + // 1.4 校验转移对象是否已经是该负责人 | |
| 226 | 233 | if (ObjUtil.equal(transferReqBO.getNewOwnerUserId(), oldOwnerPermission.getUserId())) { |
| 227 | 234 | throw exception(CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS, bizTypeName); |
| 228 | 235 | } |
| 229 | - // 1.4 校验新负责人是否存在 | |
| 236 | + // 1.5 校验新负责人是否存在 | |
| 230 | 237 | adminUserApi.validateUserList(Collections.singletonList(transferReqBO.getNewOwnerUserId())); |
| 231 | 238 | |
| 232 | 239 | // 2. 修改新负责人的权限:已在团队中时,提升为负责人,不重复新增 | ... | ... |
yudao-module-crm/src/test/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImplTest.java
| ... | ... | @@ -15,6 +15,8 @@ import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; |
| 15 | 15 | import org.junit.jupiter.api.AfterEach; |
| 16 | 16 | import org.junit.jupiter.api.BeforeEach; |
| 17 | 17 | import org.junit.jupiter.api.Test; |
| 18 | +import org.junit.jupiter.params.ParameterizedTest; | |
| 19 | +import org.junit.jupiter.params.provider.ValueSource; | |
| 18 | 20 | import org.mockito.InjectMocks; |
| 19 | 21 | import org.mockito.Mock; |
| 20 | 22 | import org.mockito.MockedStatic; |
| ... | ... | @@ -246,6 +248,78 @@ public class CrmPermissionServiceImplTest extends BaseMockitoUnitTest { |
| 246 | 248 | assertNoPermissionWrite(); |
| 247 | 249 | } |
| 248 | 250 | |
| 251 | + // ========== 老负责人的权限级别 ========== | |
| 252 | + | |
| 253 | + @Test | |
| 254 | + public void testTransferPermission_ownerKeepOldOwnerRead() { | |
| 255 | + // mock 数据:当前用户是负责人,新负责人不在团队中 | |
| 256 | + mockPermissions(buildPermission(LOGIN_USER_PERMISSION_ID, LOGIN_USER_ID, CrmPermissionLevelEnum.OWNER)); | |
| 257 | + | |
| 258 | + // 调用:老负责人保留为 READ | |
| 259 | + permissionService.transferPermission(buildTransferReqBO(NEW_OWNER_USER_ID, CrmPermissionLevelEnum.READ.getLevel())); | |
| 260 | + // 断言:新增新负责人;老负责人(当前用户)改为 READ | |
| 261 | + verify(permissionMapper).selectByBizTypeAndBizId(BIZ_TYPE, BIZ_ID); | |
| 262 | + verifyNewOwnerInserted(); | |
| 263 | + verifyLevelUpdated(LOGIN_USER_PERMISSION_ID, CrmPermissionLevelEnum.READ); | |
| 264 | + verifyNoMoreInteractions(permissionMapper); | |
| 265 | + } | |
| 266 | + | |
| 267 | + @ParameterizedTest | |
| 268 | + @ValueSource(ints = {1, 0, -1, 4, Integer.MAX_VALUE, Integer.MIN_VALUE}) // 1 是 OWNER,其它是不存在的级别 | |
| 269 | + public void testTransferPermission_ownerInvalidOldOwnerPermissionLevel(int oldOwnerPermissionLevel) { | |
| 270 | + // mock 数据:当前用户是负责人 | |
| 271 | + mockPermissions(buildPermission(LOGIN_USER_PERMISSION_ID, LOGIN_USER_ID, CrmPermissionLevelEnum.OWNER)); | |
| 272 | + | |
| 273 | + // 调用,并断言异常:在修改任何权限前失败 | |
| 274 | + assertServiceException(() -> permissionService.transferPermission(buildTransferReqBO(NEW_OWNER_USER_ID, oldOwnerPermissionLevel)), | |
| 275 | + CRM_PERMISSION_MODEL_TRANSFER_FAIL_OLD_OWNER_PERMISSION_LEVEL_ERROR, BIZ_TYPE_NAME); | |
| 276 | + assertNoPermissionWrite(); | |
| 277 | + verifyNoInteractions(adminUserApi); | |
| 278 | + } | |
| 279 | + | |
| 280 | + @ParameterizedTest | |
| 281 | + @ValueSource(ints = {1, 0, -1, 4, Integer.MAX_VALUE, Integer.MIN_VALUE}) // 1 是 OWNER,其它是不存在的级别 | |
| 282 | + public void testTransferPermission_crmAdminInvalidOldOwnerPermissionLevel(int oldOwnerPermissionLevel) { | |
| 283 | + // mock 数据:CRM 管理员没有权限,数据的负责人是其他人(修复前:老负责人被更新回 OWNER,留下两个负责人) | |
| 284 | + mockPermissions(buildPermission(OWNER_PERMISSION_ID, OWNER_USER_ID, CrmPermissionLevelEnum.OWNER)); | |
| 285 | + mockCrmAdmin(true); | |
| 286 | + | |
| 287 | + // 调用,并断言异常:在修改任何权限前失败 | |
| 288 | + assertServiceException(() -> permissionService.transferPermission(buildTransferReqBO(NEW_OWNER_USER_ID, oldOwnerPermissionLevel)), | |
| 289 | + CRM_PERMISSION_MODEL_TRANSFER_FAIL_OLD_OWNER_PERMISSION_LEVEL_ERROR, BIZ_TYPE_NAME); | |
| 290 | + assertNoPermissionWrite(); | |
| 291 | + verifyNoInteractions(adminUserApi); | |
| 292 | + } | |
| 293 | + | |
| 294 | + @Test | |
| 295 | + public void testTransferPermission_teamMemberDeniedBeforeOldOwnerPermissionLevel() { | |
| 296 | + // mock 数据:当前用户只有 WRITE 团队权限,不是 CRM 管理员 | |
| 297 | + mockPermissions(buildPermission(OWNER_PERMISSION_ID, OWNER_USER_ID, CrmPermissionLevelEnum.OWNER), | |
| 298 | + buildPermission(LOGIN_USER_PERMISSION_ID, LOGIN_USER_ID, CrmPermissionLevelEnum.WRITE)); | |
| 299 | + mockCrmAdmin(false); | |
| 300 | + | |
| 301 | + // 调用,并断言异常:先校验数据权限,再校验老负责人的权限级别 | |
| 302 | + assertServiceException(() -> permissionService.transferPermission(buildTransferReqBO(NEW_OWNER_USER_ID, | |
| 303 | + CrmPermissionLevelEnum.OWNER.getLevel())), | |
| 304 | + CRM_PERMISSION_DENIED, BIZ_TYPE_NAME); | |
| 305 | + assertNoPermissionWrite(); | |
| 306 | + verifyNoInteractions(adminUserApi); | |
| 307 | + } | |
| 308 | + | |
| 309 | + @Test | |
| 310 | + public void testTransferPermission_crmAdminOldOwnerPermissionLevelBeforeOwnerNotExists() { | |
| 311 | + // mock 数据:CRM 管理员有 WRITE 团队权限,但数据缺少负责人 | |
| 312 | + mockPermissions(buildPermission(LOGIN_USER_PERMISSION_ID, LOGIN_USER_ID, CrmPermissionLevelEnum.WRITE)); | |
| 313 | + mockCrmAdmin(true); | |
| 314 | + | |
| 315 | + // 调用,并断言异常:先校验老负责人的权限级别(请求参数),再校验数据的负责人 | |
| 316 | + assertServiceException(() -> permissionService.transferPermission(buildTransferReqBO(NEW_OWNER_USER_ID, | |
| 317 | + CrmPermissionLevelEnum.OWNER.getLevel())), | |
| 318 | + CRM_PERMISSION_MODEL_TRANSFER_FAIL_OLD_OWNER_PERMISSION_LEVEL_ERROR, BIZ_TYPE_NAME); | |
| 319 | + assertNoPermissionWrite(); | |
| 320 | + verifyNoInteractions(adminUserApi); | |
| 321 | + } | |
| 322 | + | |
| 249 | 323 | private void mockCrmAdmin(boolean crmAdmin) { |
| 250 | 324 | springUtilMockedStatic.when(() -> SpringUtil.getBean(PermissionCommonApi.class)).thenReturn(permissionCommonApi); |
| 251 | 325 | when(permissionCommonApi.hasAnyRoles(LOGIN_USER_ID, RoleCodeEnum.CRM_ADMIN.getCode())).thenReturn(crmAdmin); | ... | ... |