Commit e765fc2972e3b65b0309f4a68412ffd114b10ee0

Authored by zichun
1 parent 15d5257b

feat(usr): UserService.updateUser 三重校验 + 权限组 replace REQ-USR-002

REQ-USR-002
backend/src/main/java/com/example/erp/module/usr/service/UserService.java
@@ -4,10 +4,12 @@ import com.example.erp.common.vo.PageVO; @@ -4,10 +4,12 @@ import com.example.erp.common.vo.PageVO;
4 import com.example.erp.config.UserPrincipal; 4 import com.example.erp.config.UserPrincipal;
5 import com.example.erp.module.usr.dto.UserCreateReqDTO; 5 import com.example.erp.module.usr.dto.UserCreateReqDTO;
6 import com.example.erp.module.usr.dto.UserListQueryDTO; 6 import com.example.erp.module.usr.dto.UserListQueryDTO;
  7 +import com.example.erp.module.usr.dto.UserUpdateReqDTO;
7 import com.example.erp.module.usr.vo.PermissionGroupVO; 8 import com.example.erp.module.usr.vo.PermissionGroupVO;
8 import com.example.erp.module.usr.vo.StaffVO; 9 import com.example.erp.module.usr.vo.StaffVO;
9 import com.example.erp.module.usr.vo.UserCreateRespVO; 10 import com.example.erp.module.usr.vo.UserCreateRespVO;
10 import com.example.erp.module.usr.vo.UserListItemVO; 11 import com.example.erp.module.usr.vo.UserListItemVO;
  12 +import com.example.erp.module.usr.vo.UserUpdateRespVO;
11 13
12 import java.util.List; 14 import java.util.List;
13 15
@@ -20,4 +22,6 @@ public interface UserService { @@ -20,4 +22,6 @@ public interface UserService {
20 List<PermissionGroupVO> getPermissionGroups(String brandId); 22 List<PermissionGroupVO> getPermissionGroups(String brandId);
21 23
22 PageVO<UserListItemVO> getUserList(UserListQueryDTO query, String brandId); 24 PageVO<UserListItemVO> getUserList(UserListQueryDTO query, String brandId);
  25 +
  26 + UserUpdateRespVO updateUser(String userId, UserUpdateReqDTO req, UserPrincipal principal);
23 } 27 }
backend/src/main/java/com/example/erp/module/usr/service/impl/UserServiceImpl.java
1 package com.example.erp.module.usr.service.impl; 1 package com.example.erp.module.usr.service.impl;
2 2
3 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 3 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  4 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
4 import com.baomidou.mybatisplus.core.metadata.IPage; 5 import com.baomidou.mybatisplus.core.metadata.IPage;
5 import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 6 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
6 import com.example.erp.common.constants.UsrErrorCode; 7 import com.example.erp.common.constants.UsrErrorCode;
@@ -9,6 +10,7 @@ import com.example.erp.common.vo.PageVO; @@ -9,6 +10,7 @@ import com.example.erp.common.vo.PageVO;
9 import com.example.erp.config.UserPrincipal; 10 import com.example.erp.config.UserPrincipal;
10 import com.example.erp.module.usr.dto.UserCreateReqDTO; 11 import com.example.erp.module.usr.dto.UserCreateReqDTO;
11 import com.example.erp.module.usr.dto.UserListQueryDTO; 12 import com.example.erp.module.usr.dto.UserListQueryDTO;
  13 +import com.example.erp.module.usr.dto.UserUpdateReqDTO;
12 import com.example.erp.module.usr.entity.PermissionGroupEntity; 14 import com.example.erp.module.usr.entity.PermissionGroupEntity;
13 import com.example.erp.module.usr.entity.StaffEntity; 15 import com.example.erp.module.usr.entity.StaffEntity;
14 import com.example.erp.module.usr.entity.UserPermissionEntity; 16 import com.example.erp.module.usr.entity.UserPermissionEntity;
@@ -22,6 +24,7 @@ import com.example.erp.module.usr.vo.PermissionGroupVO; @@ -22,6 +24,7 @@ import com.example.erp.module.usr.vo.PermissionGroupVO;
22 import com.example.erp.module.usr.vo.StaffVO; 24 import com.example.erp.module.usr.vo.StaffVO;
23 import com.example.erp.module.usr.vo.UserCreateRespVO; 25 import com.example.erp.module.usr.vo.UserCreateRespVO;
24 import com.example.erp.module.usr.vo.UserListItemVO; 26 import com.example.erp.module.usr.vo.UserListItemVO;
  27 +import com.example.erp.module.usr.vo.UserUpdateRespVO;
25 import lombok.RequiredArgsConstructor; 28 import lombok.RequiredArgsConstructor;
26 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 29 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
27 import org.springframework.stereotype.Service; 30 import org.springframework.stereotype.Service;
@@ -146,4 +149,67 @@ public class UserServiceImpl implements UserService { @@ -146,4 +149,67 @@ public class UserServiceImpl implements UserService {
146 return vo; 149 return vo;
147 }).collect(Collectors.toList()); 150 }).collect(Collectors.toList());
148 } 151 }
  152 +
  153 + // REQ-USR-002: 修改用户
  154 + @Override
  155 + @Transactional
  156 + public UserUpdateRespVO updateUser(String userId, UserUpdateReqDTO req, UserPrincipal principal) {
  157 + if (!"超级管理员".equals(principal.userType())) {
  158 + throw new BizException(UsrErrorCode.PERMISSION_DENIED, "权限不足");
  159 + }
  160 +
  161 + UsrUserEntity existing = userMapper.selectOne(new LambdaQueryWrapper<UsrUserEntity>()
  162 + .eq(UsrUserEntity::getSId, userId)
  163 + .eq(UsrUserEntity::getSBrandsId, principal.brandId()));
  164 + if (existing == null) {
  165 + throw new BizException(UsrErrorCode.USER_NOT_FOUND, "用户不存在");
  166 + }
  167 +
  168 + if (principal.userId().equals(userId) && !"超级管理员".equals(req.getUserType())) {
  169 + throw new BizException(UsrErrorCode.SELF_ADMIN_CHANGE, "禁止修改自己的管理员角色");
  170 + }
  171 +
  172 + if (req.getEmployeeId() != null) {
  173 + StaffEntity staff = staffMapper.selectOne(new LambdaQueryWrapper<StaffEntity>()
  174 + .eq(StaffEntity::getSId, req.getEmployeeId())
  175 + .eq(StaffEntity::getSBrandsId, principal.brandId()));
  176 + if (staff == null) {
  177 + throw new BizException(UsrErrorCode.EMPLOYEE_NOT_FOUND, "员工不存在");
  178 + }
  179 + }
  180 +
  181 + userMapper.update(null, new LambdaUpdateWrapper<UsrUserEntity>()
  182 + .eq(UsrUserEntity::getSId, userId)
  183 + .eq(UsrUserEntity::getSBrandsId, principal.brandId())
  184 + .set(UsrUserEntity::getSUserType, req.getUserType())
  185 + .set(UsrUserEntity::getSLanguage, req.getLanguage())
  186 + .set(UsrUserEntity::getBCanEditDoc, req.isCanEditDoc() ? 1 : 0)
  187 + .set(UsrUserEntity::getBIsDisabled, req.isDisabled() ? 1 : 0)
  188 + .set(UsrUserEntity::getSEmployeeId, req.getEmployeeId()));
  189 +
  190 + userPermissionMapper.delete(new LambdaQueryWrapper<UserPermissionEntity>()
  191 + .eq(UserPermissionEntity::getSUserId, userId)
  192 + .eq(UserPermissionEntity::getSBrandsId, principal.brandId()));
  193 +
  194 + if (req.getPermGroupIds() != null && !req.getPermGroupIds().isEmpty()) {
  195 + List<UserPermissionEntity> perms = req.getPermGroupIds().stream()
  196 + .map(groupId -> {
  197 + UserPermissionEntity perm = new UserPermissionEntity();
  198 + perm.setSId(UUID.randomUUID().toString());
  199 + perm.setSBrandsId(principal.brandId());
  200 + perm.setTCreateDate(LocalDateTime.now());
  201 + perm.setSUserId(userId);
  202 + perm.setSPermGroupId(groupId);
  203 + return perm;
  204 + })
  205 + .collect(Collectors.toList());
  206 + userPermissionMapper.insert(perms);
  207 + }
  208 +
  209 + UserUpdateRespVO vo = new UserUpdateRespVO();
  210 + vo.setUserId(userId);
  211 + vo.setUsername(existing.getSUsername());
  212 + vo.setUpdatedAt(LocalDateTime.now());
  213 + return vo;
  214 + }
149 } 215 }
backend/src/test/java/com/example/erp/module/usr/UserServiceTest.java
@@ -7,7 +7,9 @@ import com.example.erp.common.vo.PageVO; @@ -7,7 +7,9 @@ import com.example.erp.common.vo.PageVO;
7 import com.example.erp.config.UserPrincipal; 7 import com.example.erp.config.UserPrincipal;
8 import com.example.erp.module.usr.dto.UserCreateReqDTO; 8 import com.example.erp.module.usr.dto.UserCreateReqDTO;
9 import com.example.erp.module.usr.dto.UserListQueryDTO; 9 import com.example.erp.module.usr.dto.UserListQueryDTO;
  10 +import com.example.erp.module.usr.dto.UserUpdateReqDTO;
10 import com.example.erp.module.usr.vo.UserListItemVO; 11 import com.example.erp.module.usr.vo.UserListItemVO;
  12 +import com.example.erp.module.usr.vo.UserUpdateRespVO;
11 import com.example.erp.module.usr.entity.StaffEntity; 13 import com.example.erp.module.usr.entity.StaffEntity;
12 import com.example.erp.module.usr.entity.UsrUserEntity; 14 import com.example.erp.module.usr.entity.UsrUserEntity;
13 import com.example.erp.module.usr.entity.UserPermissionEntity; 15 import com.example.erp.module.usr.entity.UserPermissionEntity;
@@ -187,4 +189,109 @@ class UserServiceTest { @@ -187,4 +189,109 @@ class UserServiceTest {
187 assertEquals(40400, UsrErrorCode.USER_NOT_FOUND); 189 assertEquals(40400, UsrErrorCode.USER_NOT_FOUND);
188 assertEquals(40301, UsrErrorCode.SELF_ADMIN_CHANGE); 190 assertEquals(40301, UsrErrorCode.SELF_ADMIN_CHANGE);
189 } 191 }
  192 +
  193 + @Test
  194 + void updateUser_nonAdmin_throws40300() {
  195 + UserUpdateReqDTO dto = new UserUpdateReqDTO();
  196 + dto.setUserType("普通用户");
  197 + dto.setLanguage("中文");
  198 + dto.setPermGroupIds(List.of());
  199 +
  200 + BizException ex = assertThrows(BizException.class,
  201 + () -> userService.updateUser("u-target", dto, normalUser));
  202 + assertEquals(UsrErrorCode.PERMISSION_DENIED, ex.getCode());
  203 + }
  204 +
  205 + @Test
  206 + void updateUser_userNotFound_throws40400() {
  207 + UserUpdateReqDTO dto = new UserUpdateReqDTO();
  208 + dto.setUserType("普通用户");
  209 + dto.setLanguage("中文");
  210 + dto.setPermGroupIds(List.of());
  211 + when(userMapper.selectOne(any())).thenReturn(null);
  212 +
  213 + BizException ex = assertThrows(BizException.class,
  214 + () -> userService.updateUser("u-target", dto, superAdmin));
  215 + assertEquals(UsrErrorCode.USER_NOT_FOUND, ex.getCode());
  216 + }
  217 +
  218 + @Test
  219 + void updateUser_selfAdminChange_throws40301() {
  220 + UserUpdateReqDTO dto = new UserUpdateReqDTO();
  221 + dto.setUserType("普通用户");
  222 + dto.setLanguage("中文");
  223 + dto.setPermGroupIds(List.of());
  224 + UsrUserEntity existing = new UsrUserEntity();
  225 + existing.setSId("u1");
  226 + existing.setSUsername("admin");
  227 + when(userMapper.selectOne(any())).thenReturn(existing);
  228 +
  229 + // superAdmin.userId() == "u1", target userId == "u1" → self-admin change
  230 + BizException ex = assertThrows(BizException.class,
  231 + () -> userService.updateUser("u1", dto, superAdmin));
  232 + assertEquals(UsrErrorCode.SELF_ADMIN_CHANGE, ex.getCode());
  233 + }
  234 +
  235 + @Test
  236 + void updateUser_invalidEmployee_throws40001() {
  237 + UserUpdateReqDTO dto = new UserUpdateReqDTO();
  238 + dto.setUserType("普通用户");
  239 + dto.setLanguage("中文");
  240 + dto.setEmployeeId("bad-emp");
  241 + dto.setPermGroupIds(List.of());
  242 + UsrUserEntity existing = new UsrUserEntity();
  243 + existing.setSId("u-target");
  244 + existing.setSUsername("alice");
  245 + when(userMapper.selectOne(any())).thenReturn(existing);
  246 + when(staffMapper.selectOne(any())).thenReturn(null);
  247 +
  248 + BizException ex = assertThrows(BizException.class,
  249 + () -> userService.updateUser("u-target", dto, superAdmin));
  250 + assertEquals(UsrErrorCode.EMPLOYEE_NOT_FOUND, ex.getCode());
  251 + }
  252 +
  253 + @Test
  254 + void updateUser_happyPath_updatesAndReturnsResp() {
  255 + UserUpdateReqDTO dto = new UserUpdateReqDTO();
  256 + dto.setUserType("超级管理员");
  257 + dto.setLanguage("英文");
  258 + dto.setCanEditDoc(true);
  259 + dto.setDisabled(false);
  260 + dto.setPermGroupIds(List.of("g1", "g2"));
  261 + UsrUserEntity existing = new UsrUserEntity();
  262 + existing.setSId("u-target");
  263 + existing.setSUsername("alice");
  264 + when(userMapper.selectOne(any())).thenReturn(existing);
  265 + when(userMapper.update(any(), any())).thenReturn(1);
  266 + when(userPermissionMapper.delete(any())).thenReturn(0);
  267 +
  268 + UserUpdateRespVO resp = userService.updateUser("u-target", dto, superAdmin);
  269 +
  270 + assertNotNull(resp);
  271 + assertEquals("u-target", resp.getUserId());
  272 + assertEquals("alice", resp.getUsername());
  273 + assertNotNull(resp.getUpdatedAt());
  274 + verify(userMapper).update(any(), any());
  275 + verify(userPermissionMapper).delete(any());
  276 + verify(userPermissionMapper).insert(argThat((java.util.Collection<UserPermissionEntity> c) -> c.size() == 2));
  277 + }
  278 +
  279 + @Test
  280 + void updateUser_emptyPermGroupIds_onlyDeletes() {
  281 + UserUpdateReqDTO dto = new UserUpdateReqDTO();
  282 + dto.setUserType("普通用户");
  283 + dto.setLanguage("中文");
  284 + dto.setPermGroupIds(List.of());
  285 + UsrUserEntity existing = new UsrUserEntity();
  286 + existing.setSId("u-target");
  287 + existing.setSUsername("bob");
  288 + when(userMapper.selectOne(any())).thenReturn(existing);
  289 + when(userMapper.update(any(), any())).thenReturn(1);
  290 + when(userPermissionMapper.delete(any())).thenReturn(0);
  291 +
  292 + userService.updateUser("u-target", dto, superAdmin);
  293 +
  294 + verify(userPermissionMapper).delete(any());
  295 + verify(userPermissionMapper, never()).insert(anyList());
  296 + }
190 } 297 }