From bc0efbc73e3f3ef9be6b8a6bef07fac05054f095 Mon Sep 17 00:00:00 2001 From: song-tianyang Date: Fri, 28 Jul 2023 16:00:38 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E7=B3=BB=E7=BB=9F=E8=AE=BE=E7=BD=AE):=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=A0=E9=99=A4=E7=94=A8=E6=88=B7=E6=97=B6?= =?UTF-8?q?=E6=B2=A1=E6=9C=89=E5=A4=84=E7=90=86=E6=8E=89=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E9=82=AE=E7=AE=B1=E7=9A=84=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sdk/mapper/BaseUserMapper.java | 2 + .../metersphere/sdk/mapper/BaseUserMapper.xml | 7 +- .../system/controller/UserController.java | 8 +++ .../system/service/UserService.java | 27 ++++++- .../controller/UserControllerTests.java | 70 +++++++++++-------- 5 files changed, 81 insertions(+), 33 deletions(-) diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/mapper/BaseUserMapper.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/mapper/BaseUserMapper.java index a860987659..5ba183550b 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/mapper/BaseUserMapper.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/mapper/BaseUserMapper.java @@ -26,4 +26,6 @@ public interface BaseUserMapper { List selectUnDeletedUserIdByIdList(@Param("idList") List userIdList); List selectUserByIdList(List userIds); + + long deleteUser(String id); } diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/mapper/BaseUserMapper.xml b/backend/framework/sdk/src/main/java/io/metersphere/sdk/mapper/BaseUserMapper.xml index 6d673d3642..32920ebb04 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/mapper/BaseUserMapper.xml +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/mapper/BaseUserMapper.xml @@ -1,6 +1,9 @@ + + UPDATE `user` SET `deleted` = 1, `email` = id WHERE `id` = #{id} + - INSERT INTO user(id, name, email, password, status, create_time, update_time, language, last_organization_id, + INSERT INTO user(id, name, email, password, status, create_time, update_time,update_user, language, last_organization_id, phone, source, last_project_id, create_user,deleted) VALUES (#{user.id}, #{user.name}, #{user.email}, #{user.password}, #{user.status}, #{user.createTime}, - #{user.updateTime}, #{user.language}, + #{user.updateTime},#{user.updateUser}, #{user.language}, #{user.lastOrganizationId}, #{user.phone}, #{user.source}, #{user.lastProjectId}, #{user.createUser}, #{user.deleted}) diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/controller/UserController.java b/backend/services/system-setting/src/main/java/io/metersphere/system/controller/UserController.java index d2d3d944b3..c683b36170 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/controller/UserController.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/controller/UserController.java @@ -44,24 +44,28 @@ public class UserController { private GlobalUserRoleService globalUserRoleService; @GetMapping("/get/{email}") + @Operation(summary = "通过email查找用户") @RequiresPermissions(PermissionConstants.SYSTEM_USER_ROLE_READ) public UserDTO getUser(@PathVariable String email) { return userService.getUserDTOByEmail(email); } @GetMapping("/get/global/system/role") + @Operation(summary = "查找系统级用户权限") @RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_ADD) public List getGlobalSystemRole() { return globalUserRoleService.getGlobalSystemRoleList(); } @PostMapping("/add") + @Operation(summary = "添加用户") @RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_ADD) public UserBatchCreateDTO addUser(@Validated({Created.class}) @RequestBody UserBatchCreateDTO userCreateDTO) { return userService.addUser(userCreateDTO, UserSourceEnum.LOCAL.name(), SessionUtils.getUserId()); } @PostMapping("/update") + @Operation(summary = "修改用户") @RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_UPDATE) @Log(type = OperationLogType.UPDATE, expression = "#msClass.updateLog(#request)", msClass = UserService.class) public UserEditRequest updateUser(@Validated({Updated.class}) @RequestBody UserEditRequest request) { @@ -69,6 +73,7 @@ public class UserController { } @PostMapping("/page") + @Operation(summary = "分页查找用户") @RequiresPermissions(PermissionConstants.SYSTEM_USER_READ) public Pager> list(@Validated @RequestBody BasePageRequest request) { Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), @@ -77,18 +82,21 @@ public class UserController { } @PostMapping("/update/enable") + @Operation(summary = "启用/禁用用户") @RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_UPDATE) public UserBatchProcessResponse updateUserEnable(@Validated @RequestBody UserChangeEnableRequest request) { return userService.updateUserEnable(request, SessionUtils.getSessionId()); } @PostMapping(value = "/import", consumes = {"multipart/form-data"}) + @Operation(summary = "导入用户") @RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_IMPORT) public UserImportResponse importUser(@RequestPart(value = "file", required = false) MultipartFile excelFile) { return userService.importByExcel(excelFile, UserSourceEnum.LOCAL.name(), SessionUtils.getSessionId()); } @PostMapping("/delete") + @Operation(summary = "删除用户") @Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#userBatchProcessRequest)", msClass = UserService.class) @RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_DELETE) public UserBatchProcessResponse deleteUser(@Validated @RequestBody UserChangeEnableRequest userBatchProcessRequest) { diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/service/UserService.java b/backend/services/system-setting/src/main/java/io/metersphere/system/service/UserService.java index 7409c7e580..551a2a9c5c 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/service/UserService.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/service/UserService.java @@ -32,6 +32,10 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; +import org.apache.ibatis.session.ExecutorType; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -57,6 +61,8 @@ public class UserService { private GlobalUserRoleService globalUserRoleService; @Resource private UserRoleService userRoleService; + @Resource + private SqlSessionFactory sqlSessionFactory; //批量添加用户记录日志 public List getBatchAddLogs(@Valid List userList) { @@ -273,20 +279,35 @@ public class UserService { public UserBatchProcessResponse deleteUser(@Valid @NotEmpty List userIdList) { this.checkUserInDb(userIdList); + UserBatchProcessResponse response = new UserBatchProcessResponse(); response.setTotalCount(userIdList.size()); UserExample userExample = new UserExample(); userExample.createCriteria().andIdIn(userIdList); //更新删除标志位 - response.setSuccessCount(userMapper.updateByExampleSelective(new User() {{ - setDeleted(true); - }}, userExample)); + response.setSuccessCount(this.deleteUserByList(userIdList)); //删除用户角色关系 userRoleRelationService.deleteByUserIdList(userIdList); return response; } + private int deleteUserByList(List updateUserList){ + SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); + BaseUserMapper batchDeleteMapper = sqlSession.getMapper(BaseUserMapper.class); + int insertIndex = 0; + for (String userId : updateUserList) { + batchDeleteMapper.deleteUser(userId); + insertIndex++; + if (insertIndex % 50 == 0) { + sqlSession.flushStatements(); + } + } + sqlSession.flushStatements(); + SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); + return insertIndex; + } + public LogDTO updateLog(UserEditRequest request) { User user = userMapper.selectByPrimaryKey(request.getId()); if (user != null) { diff --git a/backend/services/system-setting/src/test/java/io/metersphere/system/controller/UserControllerTests.java b/backend/services/system-setting/src/test/java/io/metersphere/system/controller/UserControllerTests.java index 416cbacb8d..0dd6928078 100644 --- a/backend/services/system-setting/src/test/java/io/metersphere/system/controller/UserControllerTests.java +++ b/backend/services/system-setting/src/test/java/io/metersphere/system/controller/UserControllerTests.java @@ -105,13 +105,6 @@ public class UserControllerTests extends BaseTest { } } - private void checkUserDeleted() throws Exception { - if (CollectionUtils.isEmpty(DELETED_USER_ID_LIST)) { - //测试数据初始化入库 - this.testUserDeleteSuccess(); - } - } - private void requestPost(String url, Object param, ResultMatcher resultMatcher) throws Exception { mockMvc.perform(MockMvcRequestBuilders.post(url) .header(SessionConstants.HEADER_TOKEN, sessionId) @@ -134,20 +127,19 @@ public class UserControllerTests extends BaseTest { } - private MvcResult responseByString(String url, String param,ResultMatcher resultMatcher) throws Exception { - return mockMvc.perform(MockMvcRequestBuilders.post(url) + private void requestResetPassword(String param, ResultMatcher resultMatcher) throws Exception { + mockMvc.perform(MockMvcRequestBuilders.post(UserTestUtils.URL_USER_RESET_PASSWORD) .header(SessionConstants.HEADER_TOKEN, sessionId) .header(SessionConstants.CSRF_TOKEN, csrfToken) .content(param) .contentType(MediaType.APPLICATION_JSON)) .andExpect(resultMatcher).andDo(print()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andReturn(); + .andExpect(content().contentType(MediaType.APPLICATION_JSON)); } - private MvcResult responseFile(String url, MockMultipartFile file) throws Exception { - return mockMvc.perform(MockMvcRequestBuilders.multipart(url) + private MvcResult responseFile(MockMultipartFile file) throws Exception { + return mockMvc.perform(MockMvcRequestBuilders.multipart(UserTestUtils.URL_USER_IMPORT) .file(file) .contentType(MediaType.MULTIPART_FORM_DATA_VALUE) .header(SessionConstants.HEADER_TOKEN, sessionId) @@ -196,6 +188,23 @@ public class UserControllerTests extends BaseTest { MvcResult mvcResult = this.responsePost(UserTestUtils.URL_USER_CREATE, userMaintainRequest); this.addUser2List(mvcResult); + + //批量添加一百多个用户 + List userCreateInfoList = new ArrayList<>(); + for (int i = 0; i < 123; i++) { + int finalI = i; + userCreateInfoList.add(new UserCreateInfo() {{ + setName("tianyang.no.batch" + finalI); + setEmail("tianyang.no.batch" + finalI + "@126.com"); + }}); + } + userMaintainRequest = UserTestUtils.getUserCreateDTO( + defaultUserRoleList, + userCreateInfoList + ); + mvcResult = this.responsePost(UserTestUtils.URL_USER_CREATE, userMaintainRequest); + this.addUser2List(mvcResult); + //含有重复的用户名称 userMaintainRequest = UserTestUtils.getUserCreateDTO( @@ -568,10 +577,10 @@ public class UserControllerTests extends BaseTest { int[] errorDataIndex = {};//出错数据的行数 UserImportResponse response;//导入返回值 //导入正常文件 - String filePath = this.getClass().getClassLoader().getResource("file/user_import_success.xlsx").getPath(); + String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/user_import_success.xlsx")).getPath(); MockMultipartFile file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath)); ExcelParseDTO userImportReportDTOByFile = userService.getUserExcelParseDTO(file); - response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class); + response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(file), UserImportResponse.class); UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex);//检查返回值 List userDTOList = this.checkImportUserInDb(userImportReportDTOByFile);//检查数据已入库 for (UserDTO item : userDTOList){ @@ -579,25 +588,25 @@ public class UserControllerTests extends BaseTest { } //导入空文件. 应当导入成功的数据为0 - filePath = this.getClass().getClassLoader().getResource("file/user_import_success_empty.xlsx").getPath(); + filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/user_import_success_empty.xlsx")).getPath(); file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath)); - response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class); + response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(file), UserImportResponse.class); importSuccessData = 0; errorDataIndex = new int[]{}; UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex); //文件内没有一条合格数据 应当导入成功的数据为0 - filePath = this.getClass().getClassLoader().getResource("file/user_import_error_all.xlsx").getPath(); + filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/user_import_error_all.xlsx")).getPath(); file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath)); - response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class); + response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(file), UserImportResponse.class); errorDataIndex = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex); //邮箱和数据库里的重复 应当导入成功的数据为8 - filePath = this.getClass().getClassLoader().getResource("file/user_import_error_email_repeat_db.xlsx").getPath(); + filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/user_import_error_email_repeat_db.xlsx")).getPath(); file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath)); userImportReportDTOByFile = userService.getUserExcelParseDTO(file); - response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class); + response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(file), UserImportResponse.class); importSuccessData = 8; errorDataIndex = new int[]{1, 7}; UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex); @@ -607,10 +616,10 @@ public class UserControllerTests extends BaseTest { } //文件内邮箱重复 应当导入成功的数据为8 - filePath = this.getClass().getClassLoader().getResource("file/user_import_error_email_repeat_in_file.xlsx").getPath(); + filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/user_import_error_email_repeat_in_file.xlsx")).getPath(); file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath)); userImportReportDTOByFile = userService.getUserExcelParseDTO(file); - response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class); + response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(file), UserImportResponse.class); errorDataIndex = new int[]{9, 10}; UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex); userDTOList = this.checkImportUserInDb(userImportReportDTOByFile);//检查数据已入库 @@ -621,7 +630,7 @@ public class UserControllerTests extends BaseTest { //文件不符合规范 应当导入成功的数据为0 filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/abcde.gif")).getPath(); file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath)); - response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class); + response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(file), UserImportResponse.class); importSuccessData = 0; errorDataIndex = new int[]{}; UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex); @@ -630,7 +639,7 @@ public class UserControllerTests extends BaseTest { filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/user_import_success_03.xls")).getPath(); file = new MockMultipartFile("file", "userImport.xlsx", MediaType.APPLICATION_OCTET_STREAM_VALUE, UserTestUtils.getFileBytes(filePath)); userImportReportDTOByFile = userService.getUserExcelParseDTO(file); - response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(UserTestUtils.URL_USER_IMPORT, file), UserImportResponse.class); + response = UserTestUtils.parseObjectFromMvcResult(this.responseFile(file), UserImportResponse.class); importSuccessData = 10;//应该导入成功的数据数量 errorDataIndex = new int[]{};//出错数据的行数 UserTestUtils.checkImportResponse(response, importSuccessData, errorDataIndex);//检查返回值 @@ -662,7 +671,7 @@ public class UserControllerTests extends BaseTest { Assertions.assertEquals(1, userMapper.updateByPrimaryKeySelective(user)); //调用重置密码的接口 - this.responseByString(UserTestUtils.URL_USER_RESET_PASSWORD, userId,status().isOk()); + this.requestResetPassword(userId,status().isOk()); //检查数据库 UserExample example = new UserExample(); example.createCriteria().andIdEqualTo(userId).andPasswordEqualTo(CodingUtil.md5(userEmail)); @@ -674,7 +683,7 @@ public class UserControllerTests extends BaseTest { @Order(8) public void testUserResetPasswordError() throws Exception { //用户不存在 - this.responseByString(UserTestUtils.URL_USER_RESET_PASSWORD, "none user",ERROR_REQUEST_MATCHER); + this.requestResetPassword("none user",ERROR_REQUEST_MATCHER); } @Test @@ -696,14 +705,16 @@ public class UserControllerTests extends BaseTest { } //记录已经删除了的用户,用于反例 DELETED_USER_ID_LIST.clear(); + USER_LIST.clear(); DELETED_USER_ID_LIST.addAll(request.getUserIdList()); + //检查删除了的用户,可以用其邮箱继续注册 + this.testAddSuccess(); } //删除失败的方法要放在删除成功方法后面执行 @Test @Order(10) public void testUserDeleteError() throws Exception { - this.checkUserDeleted(); //参数为空 UserBatchProcessRequest request = new UserBatchProcessRequest(); this.requestPost(UserTestUtils.URL_USER_DELETE, request, BAD_REQUEST_MATCHER); @@ -711,6 +722,9 @@ public class UserControllerTests extends BaseTest { request.getUserIdList().add("123456789012345678901234"); this.requestPost(UserTestUtils.URL_USER_DELETE, request, ERROR_REQUEST_MATCHER); //用户已经被删除 + if(CollectionUtils.isEmpty(DELETED_USER_ID_LIST)){ + this.testUserDeleteSuccess(); + } request.setUserIdList(DELETED_USER_ID_LIST); this.requestPost(UserTestUtils.URL_USER_DELETE, request, ERROR_REQUEST_MATCHER); }