diff --git a/backend/framework/sdk/src/main/resources/i18n/api.properties b/backend/framework/sdk/src/main/resources/i18n/api.properties index e54d93edc7..3917cd34ee 100644 --- a/backend/framework/sdk/src/main/resources/i18n/api.properties +++ b/backend/framework/sdk/src/main/resources/i18n/api.properties @@ -430,4 +430,6 @@ api_scenario_step.name.not_blank=步骤名称不能为空 api_scenario_step.resource_num.length_range=资源编号长度必须在1-50之间 tags_size_large_than=标签数量超过{0}个 + +no_permission_to_resource=无操作资源的权限 api_scenario_circular_reference_error=场景存在循环引用 \ No newline at end of file diff --git a/backend/framework/sdk/src/main/resources/i18n/api_en_US.properties b/backend/framework/sdk/src/main/resources/i18n/api_en_US.properties index 2e192f3ce2..f01036b1a1 100644 --- a/backend/framework/sdk/src/main/resources/i18n/api_en_US.properties +++ b/backend/framework/sdk/src/main/resources/i18n/api_en_US.properties @@ -437,4 +437,6 @@ api_scenario.environment_id.length_range=Environment ID length must be between 0 api_report_default_env=Default environment tags_size_large_than=The number of tags cannot exceed 10 + +no_permission_to_resource=No permission to access the resource api_scenario_circular_reference_error=There are circular references to the scenario \ No newline at end of file diff --git a/backend/framework/sdk/src/main/resources/i18n/api_zh_CN.properties b/backend/framework/sdk/src/main/resources/i18n/api_zh_CN.properties index e96d515cac..3f3fcd3c71 100644 --- a/backend/framework/sdk/src/main/resources/i18n/api_zh_CN.properties +++ b/backend/framework/sdk/src/main/resources/i18n/api_zh_CN.properties @@ -405,4 +405,6 @@ api_scenario.environment_id.length_range=环境ID长度必须在0-50之间 api_report_default_env=默认环境 tags_size_large_than=标签数量超过{0}个 + +no_permission_to_resource=没有权限访问该资源 api_scenario_circular_reference_error=场景存在循环引用 \ No newline at end of file diff --git a/backend/framework/sdk/src/main/resources/i18n/api_zh_TW.properties b/backend/framework/sdk/src/main/resources/i18n/api_zh_TW.properties index 286f30f628..cef7551339 100644 --- a/backend/framework/sdk/src/main/resources/i18n/api_zh_TW.properties +++ b/backend/framework/sdk/src/main/resources/i18n/api_zh_TW.properties @@ -404,4 +404,6 @@ api_scenario.environment_id.length_range=環境ID長度必須在0-50之間 api_report_default_env=默认環境 tags_size_large_than=標籤數量不能超過{max} + +no_permission_to_resource=無權限訪問資源 api_scenario_circular_reference_error=場景存在循環引用 \ No newline at end of file diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTaskCenterController.java b/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTaskCenterController.java index 41cc3e754b..b6b5646769 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTaskCenterController.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTaskCenterController.java @@ -2,6 +2,9 @@ package io.metersphere.api.controller; import io.metersphere.api.service.ApiTaskCenterService; import io.metersphere.sdk.constants.PermissionConstants; +import io.metersphere.sdk.constants.TaskCenterResourceType; +import io.metersphere.sdk.exception.MSException; +import io.metersphere.sdk.util.Translator; import io.metersphere.system.dto.taskcenter.TaskCenterDTO; import io.metersphere.system.dto.taskcenter.request.TaskCenterBatchRequest; import io.metersphere.system.dto.taskcenter.request.TaskCenterPageRequest; @@ -15,7 +18,9 @@ import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @author: LAN @@ -30,10 +35,13 @@ public class ApiTaskCenterController { @Resource private ApiTaskCenterService apiTaskCenterService; + private static final String PROJECT = "project"; + private static final String ORG = "org"; + private static final String SYSTEM = "system"; + @PostMapping("/api/project/real-time/page") @Operation(summary = "项目-任务中心-接口用例/场景-实时任务列表") - @RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ) public Pager> projectList(@Validated @RequestBody TaskCenterPageRequest request) { return apiTaskCenterService.getProjectPage(request, SessionUtils.getCurrentProjectId()); } @@ -54,36 +62,36 @@ public class ApiTaskCenterController { @PostMapping("/api/system/stop") @Operation(summary = "系统-任务中心-接口用例/场景-停止任务") - @RequiresPermissions(PermissionConstants.SYSTEM_TASK_CENTER_READ) public void systemStop(@Validated @RequestBody TaskCenterBatchRequest request) { + hasPermission(SYSTEM, request.getModuleType()); apiTaskCenterService.systemStop(request, SessionUtils.getUserId()); } @PostMapping("/api/org/stop") @Operation(summary = "组织-任务中心-接口用例/场景-停止任务") - @RequiresPermissions(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP) public void orgStop(@Validated @RequestBody TaskCenterBatchRequest request) { + hasPermission(ORG, request.getModuleType()); apiTaskCenterService.orgStop(request, SessionUtils.getCurrentOrganizationId(), SessionUtils.getUserId()); } @PostMapping("/api/project/stop") @Operation(summary = "项目-任务中心-接口用例/场景-停止任务") - @RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ) public void projectStop(@Validated @RequestBody TaskCenterBatchRequest request) { + hasPermission(PROJECT, request.getModuleType()); apiTaskCenterService.projectStop(request, SessionUtils.getCurrentProjectId(), SessionUtils.getUserId()); } @GetMapping("/api/project/stop/{moduleType}/{id}") @Operation(summary = "项目-任务中心-接口用例/场景-停止任务") - @RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ) public void stopById(@PathVariable String moduleType, @PathVariable String id) { + hasPermission(PROJECT, moduleType); apiTaskCenterService.stopById(moduleType, id, SessionUtils.getUserId(), OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER, "/task/center/api/project/stop"); } @GetMapping("/api/org/stop/{moduleType}/{id}") @Operation(summary = "组织-任务中心-接口用例/场景-停止任务") - @RequiresPermissions(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP) public void stopOrgById(@PathVariable String moduleType, @PathVariable String id) { + hasPermission(ORG, moduleType); apiTaskCenterService.stopById(moduleType, id, SessionUtils.getUserId(), OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER, "/task/center/api/org/stop"); } @@ -91,8 +99,34 @@ public class ApiTaskCenterController { @Operation(summary = "系统-任务中心-接口用例/场景-停止任务") @RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ) public void stopSystemById(@PathVariable String moduleType,@PathVariable String id) { + hasPermission(SYSTEM, moduleType); apiTaskCenterService.stopById(moduleType ,id, SessionUtils.getUserId(), OperationLogModule.SETTING_SYSTEM_TASK_CENTER, "/task/center/api/system/stop"); } + private void hasPermission(String type, String moduleType) { + Map> orgPermission = new HashMap<>(2); + orgPermission.put(TaskCenterResourceType.API_CASE.toString(), List.of(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP, PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE)); + orgPermission.put(TaskCenterResourceType.API_SCENARIO.toString(), List.of(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP, PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)); + Map> projectPermission = new HashMap<>(2); + projectPermission.put(TaskCenterResourceType.API_CASE.toString(), List.of(PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE)); + projectPermission.put(TaskCenterResourceType.API_SCENARIO.toString(), List.of(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)); + Map> systemPermission = new HashMap<>(2); + systemPermission.put(TaskCenterResourceType.API_CASE.toString(), List.of(PermissionConstants.SYSTEM_TASK_CENTER_READ, PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE)); + systemPermission.put(TaskCenterResourceType.API_SCENARIO.toString(), List.of(PermissionConstants.SYSTEM_TASK_CENTER_READ, PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)); + + boolean hasPermission = switch (type) { + case ORG -> + orgPermission.get(moduleType).stream().anyMatch(item -> SessionUtils.hasPermission(SessionUtils.getCurrentOrganizationId(), SessionUtils.getCurrentProjectId(), item)); + case PROJECT -> + projectPermission.get(moduleType).stream().anyMatch(item -> SessionUtils.hasPermission(SessionUtils.getCurrentOrganizationId(), SessionUtils.getCurrentProjectId(), item)); + case SYSTEM -> + systemPermission.get(moduleType).stream().anyMatch(item -> SessionUtils.hasPermission(SessionUtils.getCurrentOrganizationId(), SessionUtils.getCurrentProjectId(), item)); + default -> false; + }; + if (!hasPermission) { + throw new MSException(Translator.get("no_permission_to_resource")); + } + } + } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiReportController.java b/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiReportController.java index 873802999a..a1d1252ccf 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiReportController.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiReportController.java @@ -78,7 +78,7 @@ public class ApiReportController { @GetMapping("/get/{id}") @Operation(summary = "接口测试-接口报告-报告获取") @CheckOwner(resourceId = "#id", resourceType = "api_report") - @RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_DEFINITION_CASE_UPDATE}, logical = Logical.OR) + @RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE}, logical = Logical.OR) public ApiReportDTO get(@PathVariable String id) { return apiReportService.get(id); } @@ -94,7 +94,7 @@ public class ApiReportController { @GetMapping("/get/detail/{reportId}/{stepId}") @Operation(summary = "接口测试-接口报告-报告详情获取") @CheckOwner(resourceId = "#reportId", resourceType = "api_report") - @RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_DEFINITION_CASE_UPDATE}, logical = Logical.OR) + @RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE}, logical = Logical.OR) public List getDetail(@PathVariable String reportId, @PathVariable String stepId) { return apiReportService.getDetail(reportId, stepId); diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/controller/scenario/ApiScenarioReportController.java b/backend/services/api-test/src/main/java/io/metersphere/api/controller/scenario/ApiScenarioReportController.java index de616cd357..63b3c27d80 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/controller/scenario/ApiScenarioReportController.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/controller/scenario/ApiScenarioReportController.java @@ -77,7 +77,7 @@ public class ApiScenarioReportController { @GetMapping("/get/{id}") @Operation(summary = "接口测试-接口报告-报告获取") @CheckOwner(resourceId = "#id", resourceType = "api_scenario_report") - @RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_SCENARIO_UPDATE}, logical = Logical.OR) + @RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_SCENARIO_EXECUTE}, logical = Logical.OR) public ApiScenarioReportDTO get(@PathVariable String id) { return apiScenarioReportService.get(id); } @@ -93,7 +93,7 @@ public class ApiScenarioReportController { @GetMapping("/get/detail/{reportId}/{stepId}") @Operation(summary = "接口测试-接口报告-报告详情获取") @CheckOwner(resourceId = "#reportId", resourceType = "api_scenario_report") - @RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_SCENARIO_UPDATE}, logical = Logical.OR) + @RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_SCENARIO_EXECUTE}, logical = Logical.OR) public List getDetail(@PathVariable String reportId, @PathVariable String stepId) { return apiScenarioReportService.getDetail(reportId, stepId); diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiReportMapper.xml b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiReportMapper.xml index 0347c695af..133d212df9 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiReportMapper.xml +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiReportMapper.xml @@ -142,6 +142,18 @@ and api_report.update_user in + + and api_report.project_id in + + #{value} + + + + and project.organization_id in + + #{value} + + @@ -179,6 +191,7 @@ LEFT JOIN api_test_case_record a ON api_report.id = a.api_report_id LEFT JOIN api_test_case c ON a.api_test_case_id = c.id LEFT JOIN test_resource_pool t ON api_report.pool_id = t.id + left join project on api_report.project_id = project.id where api_report.deleted = false and api_report.test_plan_id = 'NONE' and api_report.start_time BETWEEN #{startTime} AND #{endTime} diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioReportMapper.java b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioReportMapper.java index a6f50614da..a6ee000931 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioReportMapper.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioReportMapper.java @@ -48,7 +48,7 @@ public interface ExtApiScenarioReportMapper { ApiScenarioBlob getScenarioBlob(String id); - void updateApiScenario(List subList); + void updateApiScenario(List ids); List selectStepDeatilByReportId(String id); } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioReportMapper.xml b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioReportMapper.xml index fd9cf3c223..24e19fe940 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioReportMapper.xml +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioReportMapper.xml @@ -148,6 +148,7 @@ api_scenario_report.start_time as operationTime, api_scenario_report.create_user as operationName, api_scenario_report.trigger_mode, + api_scenario_report.script_identifier, CASE WHEN api_scenario_report.integrated = 0 THEN @@ -169,6 +170,7 @@ left join api_scenario_record a on api_scenario_report.id = a.api_scenario_report_id left JOIN api_scenario s on a.api_scenario_id = s.id left JOIN test_resource_pool t on api_scenario_report.pool_id = t.id + left join project on api_scenario_report.project_id = project.id where api_scenario_report.deleted = false and api_scenario_report.test_plan_id = 'NONE' and api_scenario_report.start_time BETWEEN #{startTime} AND #{endTime} @@ -265,6 +267,18 @@ and api_scenario_report.update_user in + + and api_scenario_report.project_id in + + #{value} + + + + and project.organization_id in + + #{value} + + diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiTaskCenterService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiTaskCenterService.java index 4175a8b6a7..298e939a62 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiTaskCenterService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiTaskCenterService.java @@ -203,7 +203,7 @@ public class ApiTaskCenterService { } public void systemStop(TaskCenterBatchRequest request, String userId) { - stopApiTask(request, null, userId, SYSTEM_STOP, HttpMethodConstants.POST.name(), OperationLogModule.SETTING_SYSTEM_TASK_CENTER); + stopApiTask(request, getSystemProjectList().stream().map(OptionDTO::getId).toList(), userId, SYSTEM_STOP, HttpMethodConstants.POST.name(), OperationLogModule.SETTING_SYSTEM_TASK_CENTER); } private void stopApiTask(TaskCenterBatchRequest request, List projectIds, String userId, String path, String method, String module) { @@ -261,15 +261,17 @@ public class ApiTaskCenterService { try { LogUtils.info(String.format("开始发送停止请求到 %s 节点执行", endpoint), subList.toString()); TaskRunnerClient.stopApi(endpoint, subList); - } catch (Exception e) { if (request.getModuleType().equals(TaskCenterResourceType.API_CASE.toString())) { extApiReportMapper.updateReportStatus(subList, System.currentTimeMillis(), userId); + extApiReportMapper.updateApiCaseStatus(subList); //记录日志 saveLog(subList, userId, path, method, module, TaskCenterResourceType.API_CASE.toString()); } else if (request.getModuleType().equals(TaskCenterResourceType.API_SCENARIO.toString())) { extApiScenarioReportMapper.updateReportStatus(subList, System.currentTimeMillis(), userId); + extApiScenarioReportMapper.updateApiScenario(subList); saveLog(subList, userId, path, method, module, TaskCenterResourceType.API_SCENARIO.toString()); } + } catch (Exception e) { LogUtils.error(e); } }); diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionImportUtilService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionImportUtilService.java index 7f124fe580..beef9ad6ec 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionImportUtilService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionImportUtilService.java @@ -274,7 +274,7 @@ public class ApiDefinitionImportUtilService { Project project = projectMapper.selectByPrimaryKey(request.getProjectId()); List updateLists = new ArrayList<>(); //获取更新的日志 - getUpdateLog(request, logData, updateLists, project, operationLogs); + apiUpdateLog(request, logData, updateLists, project, operationLogs); List createLists = new ArrayList<>(); //获取新增的数据和日志 @@ -365,7 +365,7 @@ public class ApiDefinitionImportUtilService { }); } - private static void getUpdateLog(ImportRequest request, Map logData, List updateLists, Project project, List operationLogs) { + private static void apiUpdateLog(ImportRequest request, Map logData, List updateLists, Project project, List operationLogs) { if (MapUtils.isNotEmpty(logData)) { logData.forEach((k, v) -> { ApiDefinitionDTO apiDefinitionDTO = new ApiDefinitionDTO(); diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioReportLogService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioReportLogService.java index c946ad0634..ee72b7a1b1 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioReportLogService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioReportLogService.java @@ -39,7 +39,7 @@ public class ApiScenarioReportLogService { scenarioReport.getId(), null, OperationLogType.DELETE.name(), - OperationLogModule.API_REPORT, + OperationLogModule.API_TEST_REPORT_SCENARIO, scenarioReport.getName()); dto.setPath("/api/report/scenario/delete/" + scenarioReport.getId()); @@ -57,7 +57,7 @@ public class ApiScenarioReportLogService { scenarioReport.getId(), null, OperationLogType.UPDATE.name(), - OperationLogModule.API_REPORT, + OperationLogModule.API_TEST_REPORT_SCENARIO, scenarioReport.getName()); dto.setPath("/api/report/scenario/rename/" + scenarioReport.getId() + "/" + scenarioReport.getName()); @@ -77,7 +77,7 @@ public class ApiScenarioReportLogService { apiReport.getId(), userId, OperationLogType.DELETE.name(), - OperationLogModule.API_REPORT, + OperationLogModule.API_TEST_REPORT_SCENARIO, apiReport.getName()); dto.setPath("/api/report/scenario/batch/delete"); diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioReportService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioReportService.java index 6c8c771d5e..f1cf0ab5b9 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioReportService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioReportService.java @@ -261,7 +261,9 @@ public class ApiScenarioReportService { example.createCriteria().andReportIdEqualTo(id); List apiScenarioReportLogs = apiScenarioReportLogMapper.selectByExampleWithBLOBs(example); if (CollectionUtils.isNotEmpty(apiScenarioReportLogs)) { - scenarioReportDTO.setConsole(new String(apiScenarioReportLogs.getFirst().getConsole())); + //获取所有的console,生成集合 + List consoleList = apiScenarioReportLogs.stream().map(c -> new String (c.getConsole())).toList(); + scenarioReportDTO.setConsole(String.join("\n", consoleList)); } //查询资源池名称 scenarioReportDTO.setPoolName(testResourcePoolMapper.selectByPrimaryKey(scenarioReport.getPoolId()).getName()); diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/controller/TaskCenterController.java b/backend/services/system-setting/src/main/java/io/metersphere/system/controller/TaskCenterController.java index 1eefa6aa2f..28cdee68b7 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/controller/TaskCenterController.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/controller/TaskCenterController.java @@ -1,8 +1,14 @@ package io.metersphere.system.controller; import io.metersphere.sdk.constants.PermissionConstants; +import io.metersphere.sdk.constants.TaskCenterResourceType; +import io.metersphere.sdk.exception.MSException; +import io.metersphere.sdk.util.Translator; import io.metersphere.system.dto.taskcenter.TaskCenterScheduleDTO; +import io.metersphere.system.dto.taskcenter.enums.ScheduleTagType; +import io.metersphere.system.dto.taskcenter.request.TaskCenterScheduleBatchRequest; import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest; +import io.metersphere.system.log.constants.OperationLogModule; import io.metersphere.system.security.CheckOwner; import io.metersphere.system.service.TaskCenterService; import io.metersphere.system.utils.Pager; @@ -14,7 +20,9 @@ import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @author: LAN @@ -28,11 +36,13 @@ public class TaskCenterController { @Resource private TaskCenterService taskCenterService; + private static final String PROJECT = "project"; + private static final String ORG = "org"; + private static final String SYSTEM = "system"; @PostMapping("/project/schedule/page") @Operation(summary = "项目-任务中心-定时任务列表") - @RequiresPermissions(PermissionConstants.PROJECT_BASE_INFO_READ) public Pager> projectScheduleList(@Validated @RequestBody TaskCenterSchedulePageRequest request) { return taskCenterService.getProjectSchedulePage(request, SessionUtils.getCurrentProjectId()); } @@ -51,27 +61,145 @@ public class TaskCenterController { return taskCenterService.getSystemSchedulePage(request); } - @GetMapping("/schedule/delete/{id}") + @GetMapping("/system/schedule/delete/{moduleType}/{id}") @Operation(summary = "系统-任务中心-删除定时任务") @CheckOwner(resourceId = "#id", resourceType = "schedule") - public void delete(@PathVariable String id) { - taskCenterService.delete(id); + public void delete(@PathVariable String moduleType, @PathVariable String id) { + hasPermission(SYSTEM, moduleType); + taskCenterService.delete(id, SessionUtils.getUserId(), "/task/center/system/schedule/delete/", OperationLogModule.SETTING_SYSTEM_TASK_CENTER); } - @GetMapping("/schedule/switch/{id}") - @Operation(summary = "系统-任务中心-关闭/开启定时任务") + @GetMapping("/org/schedule/delete/{moduleType}/{id}") + @Operation(summary = "组织-任务中心-删除定时任务") @CheckOwner(resourceId = "#id", resourceType = "schedule") - public void enable(@PathVariable String id) { - taskCenterService.enable(id); + public void deleteOrg(@PathVariable String moduleType, @PathVariable String id) { + hasPermission(ORG, moduleType); + taskCenterService.delete(id, SessionUtils.getUserId(), "/task/center/org/schedule/delete/", OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER); } - @PostMapping("/schedule/update/{id}") + @GetMapping("/project/schedule/delete/{moduleType}/{id}") + @Operation(summary = "项目-任务中心-删除定时任务") + @CheckOwner(resourceId = "#id", resourceType = "schedule") + public void deleteProject(@PathVariable String moduleType, @PathVariable String id) { + hasPermission(PROJECT, moduleType); + taskCenterService.delete(id, SessionUtils.getUserId(), "/task/center/project/schedule/delete/", OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER); + } + + @GetMapping("/system/schedule/switch/{moduleType}/{id}") + @Operation(summary = "系统-任务中心-定时任务开启关闭") + @CheckOwner(resourceId = "#id", resourceType = "schedule") + public void enable(@PathVariable String moduleType, @PathVariable String id) { + hasPermission(SYSTEM, moduleType); + taskCenterService.enable(id, SessionUtils.getUserId(), "/task/center/system/schedule/switch/", OperationLogModule.SETTING_SYSTEM_TASK_CENTER); + } + + + @GetMapping("/org/schedule/switch/{moduleType}/{id}") + @Operation(summary = "组织-任务中心-定时任务开启关闭") + @CheckOwner(resourceId = "#id", resourceType = "schedule") + public void enableOrg(@PathVariable String moduleType, @PathVariable String id) { + hasPermission(ORG, moduleType); + taskCenterService.enable(id, SessionUtils.getUserId(), "/task/center/org/schedule/switch/", OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER); + } + + @GetMapping("/project/schedule/switch/{moduleType}/{id}") + @Operation(summary = "项目-任务中心-定时任务开启关闭") + @CheckOwner(resourceId = "#id", resourceType = "schedule") + public void enableProject(@PathVariable String moduleType, @PathVariable String id) { + hasPermission(PROJECT, moduleType); + taskCenterService.enable(id, SessionUtils.getUserId(), "/task/center/project/schedule/switch/", OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER); + } + + @PostMapping("/system/schedule/update/{moduleType}/{id}") @Operation(summary = "系统-任务中心-修改定时任务") @CheckOwner(resourceId = "#id", resourceType = "schedule") - public void update(@PathVariable String id, @RequestBody Object cron) { - taskCenterService.update(id, cron.toString()); + public void update(@PathVariable String moduleType, @PathVariable String id, @RequestBody Object cron) { + hasPermission(SYSTEM, moduleType); + taskCenterService.update(id, cron.toString(), SessionUtils.getUserId(), "/task/center/system/schedule/update/", OperationLogModule.SETTING_SYSTEM_TASK_CENTER); } + @PostMapping("/org/schedule/update/{moduleType}/{id}") + @Operation(summary = "组织-任务中心-修改定时任务") + @CheckOwner(resourceId = "#id", resourceType = "schedule") + public void updateOrg(@PathVariable String moduleType, @PathVariable String id, @RequestBody Object cron) { + hasPermission(ORG, moduleType); + taskCenterService.update(id, cron.toString(), SessionUtils.getUserId(), "/task/center/org/schedule/update/", OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER); + } + + @PostMapping("/project/schedule/update/{moduleType}/{id}") + @Operation(summary = "项目-任务中心-修改定时任务") + @CheckOwner(resourceId = "#id", resourceType = "schedule") + public void updateProject(@PathVariable String moduleType, @PathVariable String id, @RequestBody Object cron) { + hasPermission(PROJECT, moduleType); + taskCenterService.update(id, cron.toString(), SessionUtils.getUserId(), "/task/center/project/schedule/update/", OperationLogModule.PROJECT_PROJECT_MANAGER); + } + + @PostMapping("/system/schedule/batch-enable") + @Operation(summary = "系统-任务中心-定时任务批量开启") + public void batchEnable(@Validated @RequestBody TaskCenterScheduleBatchRequest request) { + hasPermission(SYSTEM, request.getScheduleTagType()); + taskCenterService.batchEnable(request, SessionUtils.getUserId(), "/task/center/system/schedule/batch-enable", OperationLogModule.SETTING_SYSTEM_TASK_CENTER, true); + } + + @PostMapping("/org/schedule/batch-enable") + @Operation(summary = "组织-任务中心-定时任务批量开启") + public void batchOrgEnable(@Validated @RequestBody TaskCenterScheduleBatchRequest request) { + hasPermission(ORG, request.getScheduleTagType()); + taskCenterService.batchEnableOrg(request, SessionUtils.getUserId(), SessionUtils.getCurrentOrganizationId(), "/task/center/org/schedule/batch-enable", OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER, true); + } + + @PostMapping("/project/schedule/batch-enable") + @Operation(summary = "项目-任务中心-定时任务批量开启") + public void batchProjectEnable(@Validated @RequestBody TaskCenterScheduleBatchRequest request) { + hasPermission(PROJECT, request.getScheduleTagType()); + taskCenterService.batchEnableProject(request, SessionUtils.getUserId(), SessionUtils.getCurrentProjectId(), "/task/center/project/schedule/batch-enable", OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER, true); + } + + @PostMapping("/system/schedule/batch-disable") + @Operation(summary = "系统-任务中心-定时任务批量关闭") + public void batchDisable(@Validated @RequestBody TaskCenterScheduleBatchRequest request) { + hasPermission(SYSTEM, request.getScheduleTagType()); + taskCenterService.batchEnable(request, SessionUtils.getUserId(), "/task/center/system/schedule/batch-disable", OperationLogModule.SETTING_SYSTEM_TASK_CENTER, false); + } + + @PostMapping("/org/schedule/batch-disable") + @Operation(summary = "组织-任务中心-定时任务批量关闭") + public void batchOrgDisable(@Validated @RequestBody TaskCenterScheduleBatchRequest request) { + hasPermission(ORG, request.getScheduleTagType()); + taskCenterService.batchEnableOrg(request, SessionUtils.getUserId(), SessionUtils.getCurrentOrganizationId(), "/task/center/org/schedule/batch-disable", OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER, false); + } + + @PostMapping("/project/schedule/batch-disable") + @Operation(summary = "项目-任务中心-定时任务批量关闭") + public void batchProjectDisable(@Validated @RequestBody TaskCenterScheduleBatchRequest request) { + hasPermission(PROJECT, request.getScheduleTagType()); + taskCenterService.batchEnableProject(request, SessionUtils.getUserId(), SessionUtils.getCurrentProjectId(), "/task/center/project/schedule/batch-disable", OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER, false); + } + + private void hasPermission(String type, String moduleType) { + Map> projectPermission = new HashMap<>(2); + projectPermission.put(ScheduleTagType.API_IMPORT.toString(), List.of(PermissionConstants.PROJECT_API_DEFINITION_IMPORT)); + projectPermission.put(TaskCenterResourceType.API_SCENARIO.toString(), List.of(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)); + Map> orgPermission = new HashMap<>(2); + orgPermission.put(ScheduleTagType.API_IMPORT.toString(), List.of(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP, PermissionConstants.PROJECT_API_DEFINITION_IMPORT)); + orgPermission.put(TaskCenterResourceType.API_SCENARIO.toString(), List.of(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP, PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)); + Map> systemPermission = new HashMap<>(2); + systemPermission.put(ScheduleTagType.API_IMPORT.toString(), List.of(PermissionConstants.SYSTEM_TASK_CENTER_READ, PermissionConstants.PROJECT_API_DEFINITION_IMPORT)); + systemPermission.put(TaskCenterResourceType.API_SCENARIO.toString(), List.of(PermissionConstants.SYSTEM_TASK_CENTER_READ, PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)); + + boolean hasPermission = switch (type) { + case ORG -> + orgPermission.get(moduleType).stream().anyMatch(item -> SessionUtils.hasPermission(SessionUtils.getCurrentOrganizationId(), SessionUtils.getCurrentProjectId(), item)); + case PROJECT -> + projectPermission.get(moduleType).stream().anyMatch(item -> SessionUtils.hasPermission(SessionUtils.getCurrentOrganizationId(), SessionUtils.getCurrentProjectId(), item)); + case SYSTEM -> + systemPermission.get(moduleType).stream().anyMatch(item -> SessionUtils.hasPermission(SessionUtils.getCurrentOrganizationId(), SessionUtils.getCurrentProjectId(), item)); + default -> false; + }; + if (!hasPermission) { + throw new MSException(Translator.get("no_permission_to_resource")); + } + } } diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/dto/taskcenter/TaskCenterDTO.java b/backend/services/system-setting/src/main/java/io/metersphere/system/dto/taskcenter/TaskCenterDTO.java index e8e272a499..cd36a70a8d 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/dto/taskcenter/TaskCenterDTO.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/dto/taskcenter/TaskCenterDTO.java @@ -46,6 +46,9 @@ public class TaskCenterDTO implements Serializable { @Schema(description = "执行状态/SUCCESS/ERROR") private String status; + @Schema(description = "脚本标识") + private String scriptIdentifier; + @Schema(description = "操作人") private String operationName; diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/dto/taskcenter/enums/ScheduleTagType.java b/backend/services/system-setting/src/main/java/io/metersphere/system/dto/taskcenter/enums/ScheduleTagType.java index f966c10df5..2ecf31269b 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/dto/taskcenter/enums/ScheduleTagType.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/dto/taskcenter/enums/ScheduleTagType.java @@ -9,9 +9,10 @@ import java.util.List; */ public enum ScheduleTagType { API_IMPORT("API_IMPORT"), - TEST_RESOURCE("API_SCENARIO", "UI_SCENARIO", "LOAD_TEST", "TEST_PLAN"), - - ORDER("CLEAN_REPORT", "BUG_SYNC"); + API_SCENARIO("API_SCENARIO"), + UI_SCENARIO("UI_TEST"), + LOAD_TEST("LOAD_TEST"), + TEST_PLAN("TEST_PLAN"); private List names; diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/dto/taskcenter/request/TaskCenterScheduleBatchRequest.java b/backend/services/system-setting/src/main/java/io/metersphere/system/dto/taskcenter/request/TaskCenterScheduleBatchRequest.java new file mode 100644 index 0000000000..3a67646e5f --- /dev/null +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/dto/taskcenter/request/TaskCenterScheduleBatchRequest.java @@ -0,0 +1,21 @@ +package io.metersphere.system.dto.taskcenter.request; + +import io.metersphere.system.dto.table.TableBatchProcessDTO; +import io.metersphere.system.dto.taskcenter.enums.ScheduleTagType; +import io.metersphere.system.valid.EnumValue; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +public class TaskCenterScheduleBatchRequest extends TableBatchProcessDTO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "所属模块", requiredMode = Schema.RequiredMode.REQUIRED) + @EnumValue(enumClass = ScheduleTagType.class) + private String scheduleTagType = ScheduleTagType.API_IMPORT.toString(); + +} diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/log/constants/OperationLogModule.java b/backend/services/system-setting/src/main/java/io/metersphere/system/log/constants/OperationLogModule.java index 48d9ffd9fb..83cad4f0e7 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/log/constants/OperationLogModule.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/log/constants/OperationLogModule.java @@ -29,7 +29,8 @@ public class OperationLogModule { public static final String API_TEST_SCENARIO_RECYCLE = "API_TEST_SCENARIO_RECYCLE"; public static final String API_TEST_MANAGEMENT_RECYCLE = "API_TEST_MANAGEMENT_RECYCLE"; - public static final String API_REPORT = "API_TEST_REPORT"; + public static final String API_REPORT = "API_TEST_REPORT_CASE"; + public static final String API_TEST_REPORT_SCENARIO = "API_TEST_REPORT_SCENARIO"; public static final String AUTH_TITLE = "AUTH_TITLE"; public static final String PROJECT_ENVIRONMENT_SETTING = "PROJECT_ENVIRONMENT_SETTING"; public static final String PROJECT_PROJECT_MANAGER = "PROJECT_PROJECT_MANAGER"; diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtScheduleMapper.java b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtScheduleMapper.java index 7f01c7be89..25d863800b 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtScheduleMapper.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtScheduleMapper.java @@ -3,7 +3,9 @@ package io.metersphere.system.mapper; import io.metersphere.api.domain.ApiScenario; import io.metersphere.api.domain.ApiTestCase; import io.metersphere.system.domain.Schedule; +import io.metersphere.system.dto.ProjectDTO; import io.metersphere.system.dto.taskcenter.TaskCenterScheduleDTO; +import io.metersphere.system.dto.taskcenter.request.TaskCenterScheduleBatchRequest; import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest; import org.apache.ibatis.annotations.Param; @@ -17,7 +19,7 @@ public interface ExtScheduleMapper { * @param request 列表请求参数 * @return 定时任务列表数据 */ - List taskCenterSchedulelist(@Param("request") TaskCenterSchedulePageRequest request, @Param("projectIds") List projectIds, @Param("resourceTypes") List resourceTypes); + List taskCenterSchedulelist(@Param("request") TaskCenterSchedulePageRequest request, @Param("projectIds") List projectIds); List getApiTestCaseListByIds(@Param("ids") List ids); @@ -32,4 +34,9 @@ public interface ExtScheduleMapper { long countQuartzCronTriggersByResourceId(String scheduleId); List getScheduleByLimit(@Param("start") int start, @Param("limit") int limit); + + List getOrgListByProjectIds(List ids); + + List getSchedule(@Param("request") TaskCenterScheduleBatchRequest request, @Param("projectIds") List projectIds); + } diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtScheduleMapper.xml b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtScheduleMapper.xml index 36ae0fbf8a..e2c2ecf201 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtScheduleMapper.xml +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtScheduleMapper.xml @@ -2,29 +2,13 @@ SELECT * FROM schedule ORDER BY create_time LIMIT #{start}, #{limit} + + \ No newline at end of file diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/service/TaskCenterService.java b/backend/services/system-setting/src/main/java/io/metersphere/system/service/TaskCenterService.java index 2fb378d799..8be865c05a 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/service/TaskCenterService.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/service/TaskCenterService.java @@ -4,14 +4,22 @@ import com.github.pagehelper.Page; import com.github.pagehelper.page.PageMethod; import io.metersphere.project.domain.Project; import io.metersphere.project.mapper.ProjectMapper; +import io.metersphere.sdk.constants.HttpMethodConstants; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.util.Translator; import io.metersphere.system.domain.Organization; import io.metersphere.system.domain.Schedule; +import io.metersphere.system.domain.ScheduleExample; +import io.metersphere.system.dto.ProjectDTO; +import io.metersphere.system.dto.builder.LogDTOBuilder; import io.metersphere.system.dto.sdk.OptionDTO; import io.metersphere.system.dto.taskcenter.TaskCenterScheduleDTO; import io.metersphere.system.dto.taskcenter.enums.ScheduleTagType; +import io.metersphere.system.dto.taskcenter.request.TaskCenterScheduleBatchRequest; import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest; +import io.metersphere.system.log.constants.OperationLogType; +import io.metersphere.system.log.dto.LogDTO; +import io.metersphere.system.log.service.OperationLogService; import io.metersphere.system.mapper.*; import io.metersphere.system.schedule.BaseScheduleJob; import io.metersphere.system.schedule.ScheduleService; @@ -19,11 +27,19 @@ import io.metersphere.system.utils.PageUtils; import io.metersphere.system.utils.Pager; import jakarta.annotation.Resource; import org.apache.commons.lang3.StringUtils; -import org.quartz.*; +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.quartz.JobKey; +import org.quartz.TriggerKey; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -62,6 +78,10 @@ public class TaskCenterService { @Resource ScheduleService scheduleService; + @Resource + OperationLogService operationLogService; + @Resource + SqlSessionFactory sqlSessionFactory; private static final String CREATE_TIME_SORT = "create_time desc"; @@ -94,17 +114,13 @@ public class TaskCenterService { List list = new ArrayList<>(); if (request != null && !projectList.isEmpty()) { List projectIds = projectList.stream().map(OptionDTO::getId).toList(); - ScheduleTagType scheduleTagType = ScheduleTagType.valueOf(request.getScheduleTagType()); - List resourceTypes = scheduleTagType.getNames(); - if (!resourceTypes.isEmpty()) { - list = extScheduleMapper.taskCenterSchedulelist(request, projectIds, resourceTypes); - processTaskCenterSchedule(list, projectList, projectIds, request.getScheduleTagType()); - } + list = extScheduleMapper.taskCenterSchedulelist(request, projectIds); + processTaskCenterSchedule(list, projectList, projectIds); } return list; } - private void processTaskCenterSchedule(List list, List projectList, List projectIds, String scheduleTagType) { + private void processTaskCenterSchedule(List list, List projectList, List projectIds) { if (!list.isEmpty()) { // 组织 List orgListByProjectList = getOrgListByProjectIds(projectIds); @@ -122,44 +138,26 @@ public class TaskCenterService { item.setCreateUserName(userMap.getOrDefault(item.getCreateUserName(), StringUtils.EMPTY)); item.setProjectName(projectMap.getOrDefault(item.getProjectId(), StringUtils.EMPTY)); item.setOrganizationName(orgMap.getOrDefault(item.getProjectId(), StringUtils.EMPTY)); - item.setNextTime(getNextTriggerTime(item.getValue())); }); } } - private List getProjectOption(String id){ + private List getProjectOption(String id) { return baseProjectMapper.getProjectOptionsById(id); } - private List getOrgProjectList(String orgId){ + private List getOrgProjectList(String orgId) { return baseProjectMapper.getProjectOptionsByOrgId(orgId); } - private List getSystemProjectList(){ + private List getSystemProjectList() { return baseProjectMapper.getProjectOptions(); } - private List getOrgListByProjectIds(List projectIds){ + private List getOrgListByProjectIds(List projectIds) { return extOrganizationMapper.getOrgListByProjectIds(projectIds); } - /** - * 获取下次执行时间(getFireTimeAfter,也可以下下次...) - * - * @param cron cron表达式 - * @return 下次执行时间 - */ - private static Long getNextTriggerTime(String cron) { - if (!CronExpression.isValidExpression(cron)) { - return null; - } - CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("Calculate Date").withSchedule(CronScheduleBuilder.cronSchedule(cron)).build(); - Date time0 = trigger.getStartTime(); - Date time1 = trigger.getFireTimeAfter(time0); - return time1 == null ? 0 : time1.getTime(); - } - - /** * 查看项目是否存在 * @@ -186,12 +184,13 @@ public class TaskCenterService { return organization; } - public void delete(String id) { + public void delete(String id, String userId, String path, String module) { Schedule schedule = checkScheduleExit(id); if (ScheduleTagType.API_IMPORT.getNames().contains(schedule.getResourceType())) { extSwaggerMapper.deleteByPrimaryKey(schedule.getResourceId()); } scheduleService.deleteByResourceId(schedule.getResourceId(), schedule.getJob()); + saveLog(List.of(schedule), userId, path, HttpMethodConstants.GET.name(), module, OperationLogType.DELETE.name()); } private Schedule checkScheduleExit(String id) { @@ -202,21 +201,91 @@ public class TaskCenterService { return schedule; } - public void enable(String id) { + public void enable(String id, String userId, String path, String module) { Schedule schedule = checkScheduleExit(id); schedule.setEnable(!schedule.getEnable()); scheduleService.editSchedule(schedule); scheduleService.addOrUpdateCronJob(schedule, new JobKey(schedule.getKey(), schedule.getJob()), - new TriggerKey(schedule.getKey(),schedule.getJob()), BaseScheduleJob.class); - - + new TriggerKey(schedule.getKey(), schedule.getJob()), BaseScheduleJob.class); + saveLog(List.of(schedule), userId, path, HttpMethodConstants.GET.name(), module, OperationLogType.UPDATE.name()); } - public void update(String id, String cron) { + public void update(String id, String cron, String userId, String path, String module) { Schedule schedule = checkScheduleExit(id); schedule.setValue(cron); scheduleService.editSchedule(schedule); scheduleService.addOrUpdateCronJob(schedule, new JobKey(schedule.getKey(), schedule.getJob()), - new TriggerKey(schedule.getKey(),schedule.getJob()), schedule.getJob().getClass()); + new TriggerKey(schedule.getKey(), schedule.getJob()), schedule.getJob().getClass()); + saveLog(List.of(schedule), userId, path, HttpMethodConstants.POST.name(), module, OperationLogType.UPDATE.name()); + } + + private void saveLog(List scheduleList, String userId, String path, String method, String module, String operationType) { + //取出所有的项目id + if (scheduleList.isEmpty()) { + return; + } + List projectIds = scheduleList.stream().map(Schedule::getProjectId).distinct().toList(); + //根据项目id取出组织id + List orgList = extScheduleMapper.getOrgListByProjectIds(projectIds); + //生成map key:项目id value:组织id + Map orgMap = orgList.stream().collect(Collectors.toMap(ProjectDTO::getId, ProjectDTO::getOrganizationId)); + List logs = new ArrayList<>(); + scheduleList.forEach(s -> { + LogDTO dto = LogDTOBuilder.builder() + .projectId(s.getProjectId()) + .organizationId(orgMap.get(s.getProjectId())) + .type(operationType) + .module(module) + .method(method) + .path(path) + .sourceId(s.getResourceId()) + .content(s.getName()) + .createUser(userId) + .build().getLogDTO(); + logs.add(dto); + }); + operationLogService.batchAdd(logs); + } + + public void batchEnable(TaskCenterScheduleBatchRequest request, String userId, String path, String module, boolean enable) { + List projectList = getSystemProjectList(); + batchOperation(request, userId, path, module, projectList, enable); + } + + public void batchEnableOrg(TaskCenterScheduleBatchRequest request, String userId, String orgId, String path, String module, boolean enable) { + List projectList = getOrgProjectList(orgId); + batchOperation(request, userId, path, module, projectList, enable); + + } + + private void batchOperation(TaskCenterScheduleBatchRequest request, String userId, String path, String module, List projectList, boolean enable) { + List scheduleList = new ArrayList<>(); + if (request.isSelectAll()) { + List projectIds = projectList.stream().map(OptionDTO::getId).toList(); + scheduleList = extScheduleMapper.getSchedule(request, projectIds); + } else { + ScheduleExample example = new ScheduleExample(); + example.createCriteria().andIdIn(request.getSelectIds()).andResourceTypeEqualTo(request.getScheduleTagType()); + scheduleList = scheduleMapper.selectByExample(example); + } + //过滤掉不需要的 和已经开启过的 + scheduleList = scheduleList.stream().filter(s -> s.getEnable() != enable || !request.getExcludeIds().contains(s.getId())).collect(Collectors.toList()); + + SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); + ScheduleMapper batchMapper = sqlSession.getMapper(ScheduleMapper.class); + scheduleList.forEach(s -> { + s.setEnable(enable); + batchMapper.updateByPrimaryKeySelective(s); + scheduleService.addOrUpdateCronJob(s, new JobKey(s.getKey(), s.getJob()), + new TriggerKey(s.getKey(), s.getJob()), BaseScheduleJob.class); + }); + sqlSession.flushStatements(); + SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); + saveLog(scheduleList, userId, path, HttpMethodConstants.POST.name(), module, OperationLogType.UPDATE.name()); + } + + public void batchEnableProject(TaskCenterScheduleBatchRequest request, String userId, String projectId, String path, String module, boolean enable) { + List projectList = getProjectOption(projectId); + batchOperation(request, userId, path, module, projectList, enable); } } diff --git a/backend/services/system-setting/src/test/java/io/metersphere/system/controller/TaskCenterScheduleControllerTests.java b/backend/services/system-setting/src/test/java/io/metersphere/system/controller/TaskCenterScheduleControllerTests.java index 384a16e0c5..34981fd061 100644 --- a/backend/services/system-setting/src/test/java/io/metersphere/system/controller/TaskCenterScheduleControllerTests.java +++ b/backend/services/system-setting/src/test/java/io/metersphere/system/controller/TaskCenterScheduleControllerTests.java @@ -9,6 +9,7 @@ import io.metersphere.system.base.BaseTest; import io.metersphere.system.controller.handler.ResultHolder; import io.metersphere.system.domain.Schedule; import io.metersphere.system.dto.taskcenter.enums.ScheduleTagType; +import io.metersphere.system.dto.taskcenter.request.TaskCenterScheduleBatchRequest; import io.metersphere.system.dto.taskcenter.request.TaskCenterSchedulePageRequest; import io.metersphere.system.mapper.ExtSwaggerMapper; import io.metersphere.system.mapper.ScheduleMapper; @@ -68,12 +69,12 @@ class TaskCenterScheduleControllerTests extends BaseTest { doTaskCenterSchedulePage("KEYWORD", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.API_IMPORT.toString()); doTaskCenterSchedulePage("FILTER", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.API_IMPORT.toString()); - doTaskCenterSchedulePage("KEYWORD", SCHEDULED_PROJECT_PAGE, ScheduleTagType.TEST_RESOURCE.toString()); - doTaskCenterSchedulePage("FILTER", SCHEDULED_PROJECT_PAGE, ScheduleTagType.TEST_RESOURCE.toString()); - doTaskCenterSchedulePage("KEYWORD", SCHEDULED_ORG_PAGE, ScheduleTagType.TEST_RESOURCE.toString()); - doTaskCenterSchedulePage("FILTER", SCHEDULED_ORG_PAGE, ScheduleTagType.TEST_RESOURCE.toString()); - doTaskCenterSchedulePage("KEYWORD", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.TEST_RESOURCE.toString()); - doTaskCenterSchedulePage("FILTER", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.TEST_RESOURCE.toString()); + doTaskCenterSchedulePage("KEYWORD", SCHEDULED_PROJECT_PAGE, ScheduleTagType.API_SCENARIO.toString()); + doTaskCenterSchedulePage("FILTER", SCHEDULED_PROJECT_PAGE, ScheduleTagType.API_SCENARIO.toString()); + doTaskCenterSchedulePage("KEYWORD", SCHEDULED_ORG_PAGE, ScheduleTagType.API_SCENARIO.toString()); + doTaskCenterSchedulePage("FILTER", SCHEDULED_ORG_PAGE, ScheduleTagType.API_SCENARIO.toString()); + doTaskCenterSchedulePage("KEYWORD", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.API_SCENARIO.toString()); + doTaskCenterSchedulePage("FILTER", SCHEDULED_SYSTEM_PAGE, ScheduleTagType.API_SCENARIO.toString()); } private void doTaskCenterSchedulePage(String search, String url, String scheduleTagType) throws Exception { @@ -160,14 +161,16 @@ class TaskCenterScheduleControllerTests extends BaseTest { String scheduleId = "1"; Schedule oldSchedule = scheduleMapper.selectByPrimaryKey(scheduleId); // @@请求成功 - this.requestGet(SCHEDULED_DELETE + scheduleId); + this.requestGet("/task/center/system/schedule/delete/" + "API_IMPORT/" + scheduleId); Schedule schedule = scheduleMapper.selectByPrimaryKey(scheduleId); Assertions.assertNull(schedule); if (ScheduleTagType.API_IMPORT.getNames().contains(oldSchedule.getType())) { int count = extSwaggerMapper.selectByPrimaryKey(oldSchedule.getResourceId()); Assertions.assertTrue(count > 0); } - this.requestGet(SCHEDULED_DELETE + "schedule-121", ERROR_REQUEST_MATCHER); + this.requestGet("/task/center/org/schedule/delete/" + "API_IMPORT/" + "4"); + this.requestGet("/task/center/project/schedule/delete/" + "API_SCENARIO/" + "2"); + this.requestGet("/task/center/system/schedule/delete/" + "API_SCENARIO/" + "schedule-121", ERROR_REQUEST_MATCHER); } @Test @@ -191,8 +194,25 @@ class TaskCenterScheduleControllerTests extends BaseTest { scheduleService.getSchedule(schedule.getId()); scheduleService.editSchedule(schedule); scheduleService.getScheduleByResource(schedule.getResourceId(), schedule.getJob()); - this.requestGet("/task/center/schedule/switch" + "test-schedule-switch"); - this.requestGet("/task/center/schedule/switch" + "test-schedule-switch"); - this.requestPost("/task/center/schedule/update/" + "test-schedule-switch" ,"/0 0/2 * * * ?"); + this.requestGet("/task/center/system/schedule/switch/" +"API_IMPORT/"+ "test-schedule-switch"); + this.requestGet("/task/center/org/schedule/switch/" +"API_IMPORT/"+ "test-schedule-switch"); + this.requestGet("/task/center/project/schedule/switch/" +"API_IMPORT/"+ "test-schedule-switch"); + this.requestPost("/task/center/system/schedule/update/" + "API_IMPORT/"+ "test-schedule-switch" ,"/0 0/2 * * * ?"); + this.requestPost("/task/center/org/schedule/update/" + "API_IMPORT/"+ "test-schedule-switch" ,"/0 0/2 * * * ?"); + this.requestPost("/task/center/project/schedule/update/" + "API_IMPORT/"+ "test-schedule-switch" ,"/0 0/2 * * * ?"); + + //批量操作 + TaskCenterScheduleBatchRequest request = new TaskCenterScheduleBatchRequest(); + request.setSelectIds(List.of("test-schedule-switch")); + request.setSelectAll(false); + this.requestPost("/task/center/system/schedule/batch-enable", request); + request.setSelectAll(true); + this.requestPost("/task/center/system/schedule/batch-disable", request); + this.requestPost("/task/center/org/schedule/batch-enable", request); + this.requestPost("/task/center/org/schedule/batch-disable", request); + this.requestPost("/task/center/project/schedule/batch-enable", request); + this.requestPost("/task/center/project/schedule/batch-disable", request); + + } } diff --git a/frontend/src/api/modules/project-management/taskCenter.ts b/frontend/src/api/modules/project-management/taskCenter.ts index 7361f41428..b611efec60 100644 --- a/frontend/src/api/modules/project-management/taskCenter.ts +++ b/frontend/src/api/modules/project-management/taskCenter.ts @@ -1,10 +1,21 @@ import MSR from '@/api/http'; import { + batchDisableScheduleOrgTaskUrl, + batchDisableScheduleProTaskUrl, + batchDisableScheduleSysTaskUrl, + batchEnableScheduleOrgTaskUrl, + batchEnableScheduleProTaskUrl, + batchEnableScheduleSysTaskUrl, batchStopRealOrdApiUrl, batchStopRealProjectApiUrl, batchStopRealSystemApiUrl, + deleteScheduleOrgTaskUrl, + deleteScheduleProTaskUrl, deleteScheduleSysTaskUrl, enableSchedule, + enableScheduleOrgTaskUrl, + enableScheduleProTaskUrl, + enableScheduleSysTaskUrl, scheduleOrgCenterListUrl, scheduleProCenterListUrl, scheduleSysCenterListUrl, @@ -14,7 +25,9 @@ import { taskOrgRealCenterListUrl, taskProRealCenterListUrl, taskSysRealCenterListUrl, - updateRunRulesUrl, + updateScheduleOrgTaskUrl, + updateScheduleProTaskUrl, + updateScheduleSysTaskUrl, } from '@/api/requrls/project-management/taskCenter'; import type { CommonList, TableQueryParams } from '@/models/common'; @@ -69,14 +82,69 @@ export function getScheduleProApiCaseList(data: TableQueryParams) { return MSR.post>({ url: scheduleProCenterListUrl, data }); } -export function deleteScheduleSysTask(id: string) { - return MSR.get({ url: `${deleteScheduleSysTaskUrl}/${id}` }); +// 系统删除定时任务 +export function deleteScheduleSysTask(moduleType: keyof typeof TaskCenterEnum, id: string) { + return MSR.get({ url: `${deleteScheduleSysTaskUrl}/${moduleType}/${id}` }); +} +// 组织删除定时任务 +export function deleteScheduleOrgTask(moduleType: keyof typeof TaskCenterEnum, id: string) { + return MSR.get({ url: `${deleteScheduleOrgTaskUrl}/${moduleType}/${id}` }); +} +// 项目删除定时任务 +export function deleteScheduleProTask(moduleType: keyof typeof TaskCenterEnum, id: string) { + return MSR.get({ url: `${deleteScheduleProTaskUrl}/${moduleType}/${id}` }); +} + +// 系统启用定时任务 +export function enableScheduleSysTask(moduleType: keyof typeof TaskCenterEnum, id: string) { + return MSR.get({ url: `${enableScheduleSysTaskUrl}/${moduleType}/${id}` }); +} +// 组织启用定时任务 +export function enableScheduleOrgTask(moduleType: keyof typeof TaskCenterEnum, id: string) { + return MSR.get({ url: `${enableScheduleOrgTaskUrl}/${moduleType}/${id}` }); +} +// 项目启用定时任务 +export function enableScheduleProTask(moduleType: keyof typeof TaskCenterEnum, id: string) { + return MSR.get({ url: `${enableScheduleProTaskUrl}/${moduleType}/${id}` }); +} +// 系统更新定时任务规则 +export function updateRunRules(moduleType: keyof typeof TaskCenterEnum, id: string, data: string) { + return MSR.post({ url: `${updateScheduleSysTaskUrl}/${moduleType}/${id}`, data }); +} +// 组织更新定时任务规则 +export function updateRunRulesOrg(moduleType: keyof typeof TaskCenterEnum, id: string, data: string) { + return MSR.post({ url: `${updateScheduleOrgTaskUrl}/${moduleType}/${id}`, data }); +} +// 项目更新定时任务规则 +export function updateRunRulesPro(moduleType: keyof typeof TaskCenterEnum, id: string, data: string) { + return MSR.post({ url: `${updateScheduleProTaskUrl}/${moduleType}/${id}`, data }); +} +// 系统批量开启定时任务 +export function batchEnableScheduleSysTask(data: TableQueryParams) { + return MSR.post({ url: `${batchEnableScheduleSysTaskUrl}`, data }); +} +// 组织批量开启定时任务 +export function batchEnableScheduleOrgTask(data: TableQueryParams) { + return MSR.post({ url: `${batchEnableScheduleOrgTaskUrl}`, data }); +} +// 项目批量开启定时任务 +export function batchEnableScheduleProTask(data: TableQueryParams) { + return MSR.post({ url: `${batchEnableScheduleProTaskUrl}`, data }); +} +// 系统批量关闭定时任务 +export function batchDisableScheduleSysTask(data: TableQueryParams) { + return MSR.post({ url: `${batchDisableScheduleSysTaskUrl}`, data }); +} +// 组织批量关闭定时任务 +export function batchDisableScheduleOrgTask(data: TableQueryParams) { + return MSR.post({ url: `${batchDisableScheduleOrgTaskUrl}`, data }); +} +// 项目批量关闭定时任务 +export function batchDisableScheduleProTask(data: TableQueryParams) { + return MSR.post({ url: `${batchDisableScheduleProTaskUrl}`, data }); } export function switchSchedule(id: string) { return MSR.get({ url: `${enableSchedule}/${id}` }); } -export function updateRunRules(id: string, data: string) { - return MSR.get({ url: `${updateRunRulesUrl}/${id}`, data }); -} export default {}; diff --git a/frontend/src/api/requrls/project-management/taskCenter.ts b/frontend/src/api/requrls/project-management/taskCenter.ts index 8c84725f31..e5c5cc0253 100644 --- a/frontend/src/api/requrls/project-management/taskCenter.ts +++ b/frontend/src/api/requrls/project-management/taskCenter.ts @@ -4,7 +4,7 @@ export const taskSysRealCenterListUrl = '/task/center/api/system/real-time/page' // 系统-任务中心-定时任务列表 export const scheduleSysCenterListUrl = '/task/center/system/schedule/page'; // 系统-任务中心-删除定时任务 -export const deleteScheduleSysTaskUrl = '/task/center/schedule/delete'; +// export const deleteScheduleSysTaskUrl = '/task/center/schedule/delete'; // 系统接口用例和场景停止实时任务 export const batchStopRealSystemApiUrl = '/task/center/api/system/stop'; @@ -38,3 +38,33 @@ export const stopRealOrdApiUrl = '/task/center/api/org/stop'; export const stopRealProjectApiUrl = '/task/center/api/project/stop'; // 更新定时任务运行规则 export const updateRunRulesUrl = '/task/center/schedule/update'; +// 系统定时任务 删除 +export const deleteScheduleSysTaskUrl = '/task/center/system/schedule/delete/'; +// 组织定时任务 删除 +export const deleteScheduleOrgTaskUrl = '/task/center/org/schedule/delete/'; +// 项目定时任务 删除 +export const deleteScheduleProTaskUrl = '/task/center/project/schedule/delete/'; +// 系统定时任务 启用 +export const enableScheduleSysTaskUrl = '/task/center/system/schedule/switch/'; +// 组织定时任务 启用 +export const enableScheduleOrgTaskUrl = '/task/center/org/schedule/switch/'; +// 项目定时任务 启用 +export const enableScheduleProTaskUrl = '/task/center/project/schedule/switch/'; +// 系统定时任务 更新 +export const updateScheduleSysTaskUrl = '/task/center/system/schedule/update/'; +// 组织定时任务 更新 +export const updateScheduleOrgTaskUrl = '/task/center/org/schedule/update/'; +// 项目定时任务 更新 +export const updateScheduleProTaskUrl = '/task/center/project/schedule/update/'; +// 系统定时任务 批量开启 +export const batchEnableScheduleSysTaskUrl = '/task/center/system/schedule/batch-enable'; +// 组织定时任务 批量开启 +export const batchEnableScheduleOrgTaskUrl = '/task/center/org/schedule/batch-enable'; +// 项目定时任务 批量开启 +export const batchEnableScheduleProTaskUrl = '/task/center/project/schedule/batch-enable'; +// 系统定时任务 批量关闭 +export const batchDisableScheduleSysTaskUrl = '/task/center/system/schedule/batch-disable'; +// 组织定时任务 批量关闭 +export const batchDisableScheduleOrgTaskUrl = '/task/center/org/schedule/batch-disable'; +// 项目定时任务 批量关闭 +export const batchDisableScheduleProTaskUrl = '/task/center/project/schedule/batch-disable'; diff --git a/frontend/src/auto-import.d.ts b/frontend/src/auto-import.d.ts index 5eb5ac528f..d298c3ccaa 100644 --- a/frontend/src/auto-import.d.ts +++ b/frontend/src/auto-import.d.ts @@ -62,4 +62,5 @@ declare global { declare global { // @ts-ignore export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue' + import('vue') } diff --git a/frontend/src/enums/taskCenter.ts b/frontend/src/enums/taskCenter.ts index dd4e14976a..0162944119 100644 --- a/frontend/src/enums/taskCenter.ts +++ b/frontend/src/enums/taskCenter.ts @@ -5,7 +5,7 @@ export enum TaskCenterEnum { UI_TEST = 'UI_TEST', // ui测试 LOAD_TEST = 'LOAD_TEST', // 性能测试 TEST_PLAN = 'TEST_PLAN', // 测试计划 - TEST_RESOURCE = 'TEST_RESOURCE', // 测试资源 + // TEST_RESOURCE = 'TEST_RESOURCE', // 测试资源 API_IMPORT = 'API_IMPORT', // API导入 } diff --git a/frontend/src/views/project-management/taskCenter/component/apiCase.vue b/frontend/src/views/project-management/taskCenter/component/apiCase.vue index 502630f349..0180c55448 100644 --- a/frontend/src/views/project-management/taskCenter/component/apiCase.vue +++ b/frontend/src/views/project-management/taskCenter/component/apiCase.vue @@ -1,15 +1,17 @@ diff --git a/frontend/src/views/project-management/taskCenter/component/scheduledTask.vue b/frontend/src/views/project-management/taskCenter/component/scheduledTask.vue index 1b28df85a0..4e4e061fba 100644 --- a/frontend/src/views/project-management/taskCenter/component/scheduledTask.vue +++ b/frontend/src/views/project-management/taskCenter/component/scheduledTask.vue @@ -5,14 +5,17 @@ - +
+
+ +