From e765fc2972e3b65b0309f4a68412ffd114b10ee0 Mon Sep 17 00:00:00 2001 From: zichun Date: Fri, 8 May 2026 12:08:28 +0800 Subject: [PATCH] feat(usr): UserService.updateUser 三重校验 + 权限组 replace REQ-USR-002 --- backend/src/main/java/com/example/erp/module/usr/service/UserService.java | 4 ++++ backend/src/main/java/com/example/erp/module/usr/service/impl/UserServiceImpl.java | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ backend/src/test/java/com/example/erp/module/usr/UserServiceTest.java | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 0 deletions(-) diff --git a/backend/src/main/java/com/example/erp/module/usr/service/UserService.java b/backend/src/main/java/com/example/erp/module/usr/service/UserService.java index 250676c..69dc415 100644 --- a/backend/src/main/java/com/example/erp/module/usr/service/UserService.java +++ b/backend/src/main/java/com/example/erp/module/usr/service/UserService.java @@ -4,10 +4,12 @@ import com.example.erp.common.vo.PageVO; import com.example.erp.config.UserPrincipal; import com.example.erp.module.usr.dto.UserCreateReqDTO; import com.example.erp.module.usr.dto.UserListQueryDTO; +import com.example.erp.module.usr.dto.UserUpdateReqDTO; import com.example.erp.module.usr.vo.PermissionGroupVO; import com.example.erp.module.usr.vo.StaffVO; import com.example.erp.module.usr.vo.UserCreateRespVO; import com.example.erp.module.usr.vo.UserListItemVO; +import com.example.erp.module.usr.vo.UserUpdateRespVO; import java.util.List; @@ -20,4 +22,6 @@ public interface UserService { List getPermissionGroups(String brandId); PageVO getUserList(UserListQueryDTO query, String brandId); + + UserUpdateRespVO updateUser(String userId, UserUpdateReqDTO req, UserPrincipal principal); } diff --git a/backend/src/main/java/com/example/erp/module/usr/service/impl/UserServiceImpl.java b/backend/src/main/java/com/example/erp/module/usr/service/impl/UserServiceImpl.java index 23dfe60..eb2457b 100644 --- a/backend/src/main/java/com/example/erp/module/usr/service/impl/UserServiceImpl.java +++ b/backend/src/main/java/com/example/erp/module/usr/service/impl/UserServiceImpl.java @@ -1,6 +1,7 @@ package com.example.erp.module.usr.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.example.erp.common.constants.UsrErrorCode; @@ -9,6 +10,7 @@ import com.example.erp.common.vo.PageVO; import com.example.erp.config.UserPrincipal; import com.example.erp.module.usr.dto.UserCreateReqDTO; import com.example.erp.module.usr.dto.UserListQueryDTO; +import com.example.erp.module.usr.dto.UserUpdateReqDTO; import com.example.erp.module.usr.entity.PermissionGroupEntity; import com.example.erp.module.usr.entity.StaffEntity; import com.example.erp.module.usr.entity.UserPermissionEntity; @@ -22,6 +24,7 @@ import com.example.erp.module.usr.vo.PermissionGroupVO; import com.example.erp.module.usr.vo.StaffVO; import com.example.erp.module.usr.vo.UserCreateRespVO; import com.example.erp.module.usr.vo.UserListItemVO; +import com.example.erp.module.usr.vo.UserUpdateRespVO; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; @@ -146,4 +149,67 @@ public class UserServiceImpl implements UserService { return vo; }).collect(Collectors.toList()); } + + // REQ-USR-002: 修改用户 + @Override + @Transactional + public UserUpdateRespVO updateUser(String userId, UserUpdateReqDTO req, UserPrincipal principal) { + if (!"超级管理员".equals(principal.userType())) { + throw new BizException(UsrErrorCode.PERMISSION_DENIED, "权限不足"); + } + + UsrUserEntity existing = userMapper.selectOne(new LambdaQueryWrapper() + .eq(UsrUserEntity::getSId, userId) + .eq(UsrUserEntity::getSBrandsId, principal.brandId())); + if (existing == null) { + throw new BizException(UsrErrorCode.USER_NOT_FOUND, "用户不存在"); + } + + if (principal.userId().equals(userId) && !"超级管理员".equals(req.getUserType())) { + throw new BizException(UsrErrorCode.SELF_ADMIN_CHANGE, "禁止修改自己的管理员角色"); + } + + if (req.getEmployeeId() != null) { + StaffEntity staff = staffMapper.selectOne(new LambdaQueryWrapper() + .eq(StaffEntity::getSId, req.getEmployeeId()) + .eq(StaffEntity::getSBrandsId, principal.brandId())); + if (staff == null) { + throw new BizException(UsrErrorCode.EMPLOYEE_NOT_FOUND, "员工不存在"); + } + } + + userMapper.update(null, new LambdaUpdateWrapper() + .eq(UsrUserEntity::getSId, userId) + .eq(UsrUserEntity::getSBrandsId, principal.brandId()) + .set(UsrUserEntity::getSUserType, req.getUserType()) + .set(UsrUserEntity::getSLanguage, req.getLanguage()) + .set(UsrUserEntity::getBCanEditDoc, req.isCanEditDoc() ? 1 : 0) + .set(UsrUserEntity::getBIsDisabled, req.isDisabled() ? 1 : 0) + .set(UsrUserEntity::getSEmployeeId, req.getEmployeeId())); + + userPermissionMapper.delete(new LambdaQueryWrapper() + .eq(UserPermissionEntity::getSUserId, userId) + .eq(UserPermissionEntity::getSBrandsId, principal.brandId())); + + if (req.getPermGroupIds() != null && !req.getPermGroupIds().isEmpty()) { + List perms = req.getPermGroupIds().stream() + .map(groupId -> { + UserPermissionEntity perm = new UserPermissionEntity(); + perm.setSId(UUID.randomUUID().toString()); + perm.setSBrandsId(principal.brandId()); + perm.setTCreateDate(LocalDateTime.now()); + perm.setSUserId(userId); + perm.setSPermGroupId(groupId); + return perm; + }) + .collect(Collectors.toList()); + userPermissionMapper.insert(perms); + } + + UserUpdateRespVO vo = new UserUpdateRespVO(); + vo.setUserId(userId); + vo.setUsername(existing.getSUsername()); + vo.setUpdatedAt(LocalDateTime.now()); + return vo; + } } diff --git a/backend/src/test/java/com/example/erp/module/usr/UserServiceTest.java b/backend/src/test/java/com/example/erp/module/usr/UserServiceTest.java index bde00f9..04b9ad1 100644 --- a/backend/src/test/java/com/example/erp/module/usr/UserServiceTest.java +++ b/backend/src/test/java/com/example/erp/module/usr/UserServiceTest.java @@ -7,7 +7,9 @@ import com.example.erp.common.vo.PageVO; import com.example.erp.config.UserPrincipal; import com.example.erp.module.usr.dto.UserCreateReqDTO; import com.example.erp.module.usr.dto.UserListQueryDTO; +import com.example.erp.module.usr.dto.UserUpdateReqDTO; import com.example.erp.module.usr.vo.UserListItemVO; +import com.example.erp.module.usr.vo.UserUpdateRespVO; import com.example.erp.module.usr.entity.StaffEntity; import com.example.erp.module.usr.entity.UsrUserEntity; import com.example.erp.module.usr.entity.UserPermissionEntity; @@ -187,4 +189,109 @@ class UserServiceTest { assertEquals(40400, UsrErrorCode.USER_NOT_FOUND); assertEquals(40301, UsrErrorCode.SELF_ADMIN_CHANGE); } + + @Test + void updateUser_nonAdmin_throws40300() { + UserUpdateReqDTO dto = new UserUpdateReqDTO(); + dto.setUserType("普通用户"); + dto.setLanguage("中文"); + dto.setPermGroupIds(List.of()); + + BizException ex = assertThrows(BizException.class, + () -> userService.updateUser("u-target", dto, normalUser)); + assertEquals(UsrErrorCode.PERMISSION_DENIED, ex.getCode()); + } + + @Test + void updateUser_userNotFound_throws40400() { + UserUpdateReqDTO dto = new UserUpdateReqDTO(); + dto.setUserType("普通用户"); + dto.setLanguage("中文"); + dto.setPermGroupIds(List.of()); + when(userMapper.selectOne(any())).thenReturn(null); + + BizException ex = assertThrows(BizException.class, + () -> userService.updateUser("u-target", dto, superAdmin)); + assertEquals(UsrErrorCode.USER_NOT_FOUND, ex.getCode()); + } + + @Test + void updateUser_selfAdminChange_throws40301() { + UserUpdateReqDTO dto = new UserUpdateReqDTO(); + dto.setUserType("普通用户"); + dto.setLanguage("中文"); + dto.setPermGroupIds(List.of()); + UsrUserEntity existing = new UsrUserEntity(); + existing.setSId("u1"); + existing.setSUsername("admin"); + when(userMapper.selectOne(any())).thenReturn(existing); + + // superAdmin.userId() == "u1", target userId == "u1" → self-admin change + BizException ex = assertThrows(BizException.class, + () -> userService.updateUser("u1", dto, superAdmin)); + assertEquals(UsrErrorCode.SELF_ADMIN_CHANGE, ex.getCode()); + } + + @Test + void updateUser_invalidEmployee_throws40001() { + UserUpdateReqDTO dto = new UserUpdateReqDTO(); + dto.setUserType("普通用户"); + dto.setLanguage("中文"); + dto.setEmployeeId("bad-emp"); + dto.setPermGroupIds(List.of()); + UsrUserEntity existing = new UsrUserEntity(); + existing.setSId("u-target"); + existing.setSUsername("alice"); + when(userMapper.selectOne(any())).thenReturn(existing); + when(staffMapper.selectOne(any())).thenReturn(null); + + BizException ex = assertThrows(BizException.class, + () -> userService.updateUser("u-target", dto, superAdmin)); + assertEquals(UsrErrorCode.EMPLOYEE_NOT_FOUND, ex.getCode()); + } + + @Test + void updateUser_happyPath_updatesAndReturnsResp() { + UserUpdateReqDTO dto = new UserUpdateReqDTO(); + dto.setUserType("超级管理员"); + dto.setLanguage("英文"); + dto.setCanEditDoc(true); + dto.setDisabled(false); + dto.setPermGroupIds(List.of("g1", "g2")); + UsrUserEntity existing = new UsrUserEntity(); + existing.setSId("u-target"); + existing.setSUsername("alice"); + when(userMapper.selectOne(any())).thenReturn(existing); + when(userMapper.update(any(), any())).thenReturn(1); + when(userPermissionMapper.delete(any())).thenReturn(0); + + UserUpdateRespVO resp = userService.updateUser("u-target", dto, superAdmin); + + assertNotNull(resp); + assertEquals("u-target", resp.getUserId()); + assertEquals("alice", resp.getUsername()); + assertNotNull(resp.getUpdatedAt()); + verify(userMapper).update(any(), any()); + verify(userPermissionMapper).delete(any()); + verify(userPermissionMapper).insert(argThat((java.util.Collection c) -> c.size() == 2)); + } + + @Test + void updateUser_emptyPermGroupIds_onlyDeletes() { + UserUpdateReqDTO dto = new UserUpdateReqDTO(); + dto.setUserType("普通用户"); + dto.setLanguage("中文"); + dto.setPermGroupIds(List.of()); + UsrUserEntity existing = new UsrUserEntity(); + existing.setSId("u-target"); + existing.setSUsername("bob"); + when(userMapper.selectOne(any())).thenReturn(existing); + when(userMapper.update(any(), any())).thenReturn(1); + when(userPermissionMapper.delete(any())).thenReturn(0); + + userService.updateUser("u-target", dto, superAdmin); + + verify(userPermissionMapper).delete(any()); + verify(userPermissionMapper, never()).insert(anyList()); + } } -- libgit2 0.22.2