diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/controller/NoticeTemplateController.java b/backend/services/project-management/src/main/java/io/metersphere/project/controller/NoticeTemplateController.java index e2149b3a2a..0ee945283b 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/controller/NoticeTemplateController.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/controller/NoticeTemplateController.java @@ -5,6 +5,7 @@ import io.metersphere.project.service.NoticeTemplateService; import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.dto.OptionDTO; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import org.apache.shiro.authz.annotation.RequiresPermissions; @@ -19,11 +20,12 @@ public class NoticeTemplateController { @Resource private NoticeTemplateService noticeTemplateService; - @GetMapping("get/fields/{type}") + @GetMapping("get/fields/{projectId}") @Operation(summary = "项目管理-消息设置-模版设置-获取消息模版字段") @RequiresPermissions(PermissionConstants.PROJECT_MESSAGE_READ) - public List getTemplateFields(@PathVariable String type) { - return noticeTemplateService.getTemplateFields(type); + public List getTemplateFields(@PathVariable String projectId, @Schema(description = "消息配置功能类型") + @RequestParam(value = "taskType") String taskType) { + return noticeTemplateService.getTemplateFields(projectId, taskType); } } diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/service/NoticeTemplateService.java b/backend/services/project-management/src/main/java/io/metersphere/project/service/NoticeTemplateService.java index 39c9c72476..8d111e81ec 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/service/NoticeTemplateService.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/service/NoticeTemplateService.java @@ -7,80 +7,126 @@ import io.metersphere.functional.domain.CaseReview; import io.metersphere.functional.domain.FunctionalCase; import io.metersphere.load.domain.LoadTest; import io.metersphere.plan.domain.TestPlan; +import io.metersphere.sdk.constants.TemplateScene; import io.metersphere.sdk.dto.OptionDTO; +import io.metersphere.system.domain.CustomField; +import io.metersphere.system.domain.CustomFieldExample; +import io.metersphere.system.mapper.CustomFieldMapper; import io.metersphere.system.notice.constants.NoticeConstants; import io.metersphere.ui.domain.UiScenario; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.annotation.Resource; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.reflect.FieldUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Collections; import java.util.List; @Service @Transactional(rollbackFor = Exception.class) public class NoticeTemplateService { - public List getTemplateFields(String type) { + @Resource + protected CustomFieldMapper customFieldMapper; + + public List getTemplateFields(String projectId, String taskType) { List optionDTOList = new ArrayList<>(); - switch (type) { + switch (taskType) { case NoticeConstants.TaskType.API_DEFINITION_TASK -> { Field[] allFields = FieldUtils.getAllFields(ApiDefinition.class); addOptionDto(optionDTOList, allFields); - //TODO:获取报告和自定义模版字段 + addCustomFiled(optionDTOList, projectId, TemplateScene.API.toString()); + //TODO:获取报告 } case NoticeConstants.TaskType.API_SCENARIO_TASK, NoticeConstants.TaskType.API_SCHEDULE_TASK -> { Field[] allFields = FieldUtils.getAllFields(ApiScenario.class); addOptionDto(optionDTOList, allFields); - //TODO:获取报告和自定义 + //TODO:获取报告 } case NoticeConstants.TaskType.TEST_PLAN_TASK -> { Field[] allFields = FieldUtils.getAllFields(TestPlan.class); addOptionDto(optionDTOList, allFields); - //TODO:获取报告和自定义 + addCustomFiled(optionDTOList, projectId, TemplateScene.TEST_PLAN.toString()); + //TODO:获取报告 } case NoticeConstants.TaskType.CASE_REVIEW_TASK -> { Field[] allFields = FieldUtils.getAllFields(CaseReview.class); addOptionDto(optionDTOList, allFields); - //TODO:获取报告和自定义 + //TODO:获取报告 } case NoticeConstants.TaskType.FUNCTIONAL_CASE_TASK -> { Field[] allFields = FieldUtils.getAllFields(FunctionalCase.class); addOptionDto(optionDTOList, allFields); - //TODO:获取报告和自定义 + addCustomFiled(optionDTOList, projectId, TemplateScene.FUNCTIONAL.toString()); + //TODO:获取报告 } case NoticeConstants.TaskType.BUG_TASK -> { Field[] allFields = FieldUtils.getAllFields(Bug.class); addOptionDto(optionDTOList, allFields); - //TODO:获取报告和自定义 + addCustomFiled(optionDTOList, projectId, TemplateScene.BUG.toString()); + //TODO:获取报告 } case NoticeConstants.TaskType.UI_SCENARIO_TASK -> { Field[] allFields = FieldUtils.getAllFields(UiScenario.class); addOptionDto(optionDTOList, allFields); - //TODO:获取报告和自定义 + addCustomFiled(optionDTOList, projectId, TemplateScene.UI.toString()); + //TODO:获取报告 } case NoticeConstants.TaskType.LOAD_TEST_TASK -> { Field[] allFields = FieldUtils.getAllFields(LoadTest.class); addOptionDto(optionDTOList, allFields); - //TODO:获取报告和自定义 + //TODO:获取报告 } default -> optionDTOList = new ArrayList<>(); } return optionDTOList; } + /** + * 添加自定义字段 + * @param optionDTOList optionDTOList + * @param projectId projectId + * @param scene 对应场景 + */ + private void addCustomFiled(List optionDTOList, String projectId, String scene) { + CustomFieldExample example = new CustomFieldExample(); + example.createCriteria().andScopeIdEqualTo(projectId).andSceneEqualTo(scene); + List customFields = customFieldMapper.selectByExample(example); + for (CustomField customField : customFields) { + OptionDTO optionDTO = new OptionDTO(); + optionDTO.setId(customField.getName()); + optionDTO.setName(StringUtils.isBlank(customField.getRemark()) ? "-" : customField.getRemark()); + optionDTOList.add(optionDTO); + } + } + + /** + * 添加数据库字段 + * @param optionDTOList optionDTOList + * @param allFields allFields + */ private static void addOptionDto(List optionDTOList, Field[] allFields) { + Field[] sensitiveFields = FieldUtils.getAllFields(NoticeConstants.SensitiveField.class); + ArrayList sensitiveFieldList = new ArrayList<>(sensitiveFields.length); + Collections.addAll(sensitiveFieldList, sensitiveFields); + List nameList = sensitiveFieldList.stream().map(Field::getName).toList(); for (Field allField : allFields) { OptionDTO optionDTO = new OptionDTO(); + if (nameList.contains(allField.getName())) { + continue; + } optionDTO.setId(allField.getName()); Schema annotation = allField.getAnnotation(Schema.class); if (annotation != null) { String description = annotation.description(); optionDTO.setName(description); + optionDTOList.add(optionDTO); } - optionDTOList.add(optionDTO); } } + } diff --git a/backend/services/project-management/src/test/java/io/metersphere/project/controller/NoticeTemplateControllerTests.java b/backend/services/project-management/src/test/java/io/metersphere/project/controller/NoticeTemplateControllerTests.java index 9302152423..865a4946e6 100644 --- a/backend/services/project-management/src/test/java/io/metersphere/project/controller/NoticeTemplateControllerTests.java +++ b/backend/services/project-management/src/test/java/io/metersphere/project/controller/NoticeTemplateControllerTests.java @@ -1,16 +1,18 @@ package io.metersphere.project.controller; -import io.metersphere.system.base.BaseTest; import io.metersphere.sdk.constants.SessionConstants; -import io.metersphere.system.controller.handler.ResultHolder; import io.metersphere.sdk.dto.OptionDTO; import io.metersphere.sdk.util.JSON; +import io.metersphere.system.base.BaseTest; +import io.metersphere.system.controller.handler.ResultHolder; import io.metersphere.system.notice.constants.NoticeConstants; import org.apache.commons.collections.CollectionUtils; import org.junit.jupiter.api.*; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; @@ -28,6 +30,7 @@ public class NoticeTemplateControllerTests extends BaseTest { @Test @Order(1) + @Sql(scripts = {"/dml/init_project_template.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED)) public void getTemplateFieldsSuccess() throws Exception { List typeList = new ArrayList<>(); typeList.add(NoticeConstants.TaskType.API_DEFINITION_TASK); @@ -39,29 +42,68 @@ public class NoticeTemplateControllerTests extends BaseTest { typeList.add(NoticeConstants.TaskType.BUG_TASK); typeList.add(NoticeConstants.TaskType.UI_SCENARIO_TASK); typeList.add(NoticeConstants.TaskType.LOAD_TEST_TASK); + typeList.add(NoticeConstants.TaskType.JENKINS_TASK); for (String s : typeList) { - MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/notice/template/get/fields/" + s) + MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/notice/template/get/fields/project-template-test-1") .header(SessionConstants.HEADER_TOKEN, sessionId) - .header(SessionConstants.CSRF_TOKEN, csrfToken)) + .header(SessionConstants.CSRF_TOKEN, csrfToken) + .param("taskType", s)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn(); String contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class); List projectList = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), OptionDTO.class); - Assertions.assertTrue(CollectionUtils.isNotEmpty(projectList)); + if (s.equals(NoticeConstants.TaskType.JENKINS_TASK)) { + Assertions.assertTrue(CollectionUtils.isEmpty(projectList)); + } else { + Assertions.assertTrue(CollectionUtils.isNotEmpty(projectList)); + } } } @Test @Order(2) public void getTemplateFieldsEmptySuccess() throws Exception { - MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/notice/template/get/fields/default" ) - .header(SessionConstants.HEADER_TOKEN, sessionId) - .header(SessionConstants.CSRF_TOKEN, csrfToken)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn(); - String contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); - ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class); - List projectList = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), OptionDTO.class); - Assertions.assertTrue(CollectionUtils.isEmpty(projectList)); + List typeList = new ArrayList<>(); + typeList.add(NoticeConstants.TaskType.API_DEFINITION_TASK); + typeList.add(NoticeConstants.TaskType.API_SCENARIO_TASK); + typeList.add(NoticeConstants.TaskType.API_SCHEDULE_TASK); + typeList.add(NoticeConstants.TaskType.TEST_PLAN_TASK); + typeList.add(NoticeConstants.TaskType.CASE_REVIEW_TASK); + typeList.add(NoticeConstants.TaskType.FUNCTIONAL_CASE_TASK); + typeList.add(NoticeConstants.TaskType.BUG_TASK); + typeList.add(NoticeConstants.TaskType.UI_SCENARIO_TASK); + typeList.add(NoticeConstants.TaskType.LOAD_TEST_TASK); + for (String s : typeList) { + MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/notice/template/get/fields/project-template-test-2" ) + .header(SessionConstants.HEADER_TOKEN, sessionId) + .header(SessionConstants.CSRF_TOKEN, csrfToken) + .param("taskType", s)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn(); + String contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class); + List projectList = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), OptionDTO.class); + if (s.equals(NoticeConstants.TaskType.API_DEFINITION_TASK)) { + List collect = projectList.stream().map(OptionDTO::getId).toList(); + Assertions.assertFalse(collect.contains("grade")); + } + if (s.equals(NoticeConstants.TaskType.TEST_PLAN_TASK)) { + List collect = projectList.stream().map(OptionDTO::getId).toList(); + Assertions.assertFalse(collect.contains("aa")); + } + if (s.equals(NoticeConstants.TaskType.BUG_TASK)) { + List collect = projectList.stream().map(OptionDTO::getId).toList(); + Assertions.assertFalse(collect.contains("process")); + } + if (s.equals(NoticeConstants.TaskType.FUNCTIONAL_CASE_TASK)) { + List collect = projectList.stream().map(OptionDTO::getId).toList(); + Assertions.assertFalse(collect.contains("level")); + } + if (s.equals(NoticeConstants.TaskType.UI_SCENARIO_TASK)) { + List collect = projectList.stream().map(OptionDTO::getId).toList(); + Assertions.assertFalse(collect.contains("age")); + } + } + } } diff --git a/backend/services/project-management/src/test/resources/dml/init_project_template.sql b/backend/services/project-management/src/test/resources/dml/init_project_template.sql new file mode 100644 index 0000000000..404cb37423 --- /dev/null +++ b/backend/services/project-management/src/test/resources/dml/init_project_template.sql @@ -0,0 +1,16 @@ +# 插入测试数据 +INSERT INTO organization(id, num, name, description, create_time, update_time, create_user, update_user, deleted, delete_user, delete_time) VALUE + ('organization-template-test', null, 'organization-template-test', 'organization-template-test', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'admin', 0, null, null); +INSERT INTO project (id, num, organization_id, name, description, create_user, update_user, create_time, update_time) VALUES + ('project-template-test', null, 'organization-template-test', '默认项目', '系统默认创建的项目', 'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000), + ('project-template-test-1', null, 'organization-template-test', '默认项目1', '系统默认创建的项目1', 'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000), + ('project-template-test-2', null, 'organization-template-test', '默认项目2', '系统默认创建的项目2', 'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000); + + + +INSERT INTO custom_field (id, name, scene, type, remark, create_time, update_time, create_user, scope_id) VALUES + ('custom_field_template_1', 'level', 'FUNCTIONAL', 'SELECT', '等级', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'project-template-test-1'), + ('custom_field_template_2', 'grade', 'API', 'SELECT', '', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'project-template-test-1'), + ('custom_field_template_3', 'age', 'UI', 'SELECT', '', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'project-template-test-1'), + ('custom_field_template_4', 'process', 'ISSUE', 'SELECT', '', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'project-template-test-1'), + ('custom_field_template_5', 'aa', 'TEST_PLAN', 'SELECT', '', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'project-template-test-1'); diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/notice/constants/NoticeConstants.java b/backend/services/system-setting/src/main/java/io/metersphere/system/notice/constants/NoticeConstants.java index 9a12267935..32cf1a57de 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/notice/constants/NoticeConstants.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/notice/constants/NoticeConstants.java @@ -409,6 +409,13 @@ public interface NoticeConstants { String JENKINS_TASK_EXECUTE_SUCCESSFUL = "JENKINS_TASK_EXECUTE_SUCCESSFUL"; @Schema(description = "message.title.jenkins_task_execute_failed")//Jenkins任务执行失败通知 String JENKINS_TASK_EXECUTE_FAILED = "JENKINS_TASK_EXECUTE_FAILED"; + } + interface SensitiveField { + String deleted = "deleted"; + String refId = "refId"; + String versionId = "versionId"; + String reportId = "reportId"; + String moduleId = "moduleId"; } }