From dd59a9bc1349ad0b7d5f4c1f874913200986a858 Mon Sep 17 00:00:00 2001 From: wenyann Date: Tue, 3 Aug 2021 17:08:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Swagger=E5=AE=9A=E6=97=B6=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=A2=9E=E5=8A=A0=E4=BB=BB=E5=8A=A1=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/dto/ApiTestImportRequest.java | 1 + .../api/service/ApiDefinitionService.java | 39 +++ .../commons/constants/NoticeConstants.java | 2 + .../job/sechedule/SwaggerUrlImportJob.java | 2 + .../metersphere/service/ScheduleService.java | 14 +- .../track/service/TestPlanReportService.java | 2 +- .../resources/i18n/messages_en_US.properties | 1 + .../resources/i18n/messages_zh_CN.properties | 1 + .../resources/i18n/messages_zh_TW.properties | 1 + .../main/resources/mail/SwaggerImport.html | 15 + .../resources/mail/SwaggerImportFaild.html | 15 + .../components/import/ApiSchedule.vue | 66 +++- .../import/SwaggerTaskNotification.vue | 313 ++++++++++++++++++ 13 files changed, 463 insertions(+), 9 deletions(-) create mode 100644 backend/src/main/resources/mail/SwaggerImport.html create mode 100644 backend/src/main/resources/mail/SwaggerImportFaild.html create mode 100644 frontend/src/business/components/api/definition/components/import/SwaggerTaskNotification.vue diff --git a/backend/src/main/java/io/metersphere/api/dto/ApiTestImportRequest.java b/backend/src/main/java/io/metersphere/api/dto/ApiTestImportRequest.java index 5389d3dc82..dcad5bebc0 100644 --- a/backend/src/main/java/io/metersphere/api/dto/ApiTestImportRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/ApiTestImportRequest.java @@ -16,6 +16,7 @@ public class ApiTestImportRequest { private Boolean useEnvironment; private String swaggerUrl; private String fileName; + private String resourceId; //导入策略 private String modeId; private String userId; diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java index 416a34ac50..f88b571bdc 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -38,11 +38,14 @@ import io.metersphere.log.vo.DetailColumn; import io.metersphere.log.vo.OperatingLogDetails; import io.metersphere.log.vo.StatusReference; import io.metersphere.log.vo.api.DefinitionReference; +import io.metersphere.notice.sender.NoticeModel; +import io.metersphere.notice.service.NoticeSendService; import io.metersphere.service.FileService; import io.metersphere.service.ScheduleService; import io.metersphere.service.SystemParameterService; import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest; import io.metersphere.track.request.testcase.QueryTestPlanRequest; +import io.metersphere.track.request.testreview.SaveTestCaseReviewRequest; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.session.ExecutorType; @@ -109,6 +112,8 @@ public class ApiDefinitionService { private SystemParameterService systemParameterService; @Resource private TestPlanMapper testPlanMapper; + @Resource + private NoticeSendService noticeSendService; private static Cache cache = Cache.newHardMemoryCache(0, 3600 * 24); @@ -473,6 +478,7 @@ public class ApiDefinitionService { } else { _importCreate(sameRequest, batchMapper, apiDefinition, apiTestCaseMapper, apiTestImportRequest, cases); } + return apiDefinition; } @@ -766,6 +772,7 @@ public class ApiDefinitionService { } public ApiDefinitionImport apiTestImport(MultipartFile file, ApiTestImportRequest request) { + ApiImportParser apiImportParser = ApiDefinitionImportParserFactory.getApiImportParser(request.getPlatform()); ApiDefinitionImport apiImport = null; try { @@ -773,6 +780,22 @@ public class ApiDefinitionService { } catch (Exception e) { LogUtil.error(e.getMessage(), e); MSException.throwException(Translator.get("parse_data_error")); + // 发送通知 + if (StringUtils.equals(request.getType(), "schedule")) { + String scheduleId = scheduleService.getScheduleInfo(request.getResourceId()); + String context = request.getSwaggerUrl() + "导入失败"; + Map paramMap = new HashMap<>(); + paramMap.put("url", request.getSwaggerUrl()); + NoticeModel noticeModel = NoticeModel.builder() + .context(context) + .testId(scheduleId) + .subject(Translator.get("swagger_url_scheduled_import_notification")) + .failedMailTemplate("SwaggerImportFaild") + .paramMap(paramMap) + .event(NoticeConstants.Event.IMPORT) + .build(); + noticeSendService.send(NoticeConstants.TaskType.SWAGGER_TASK, noticeModel); + } } importApi(request, apiImport); if (CollectionUtils.isNotEmpty(apiImport.getData())) { @@ -781,6 +804,22 @@ public class ApiDefinitionService { List ids = apiImport.getData().stream().map(ApiDefinitionWithBLOBs::getId).collect(Collectors.toList()); request.setId(JSON.toJSONString(ids)); } + // 发送通知 + if (StringUtils.equals(request.getType(), "schedule")) { + String scheduleId = scheduleService.getScheduleInfo(request.getResourceId()); + String context = request.getSwaggerUrl() + "导入成功"; + Map paramMap = new HashMap<>(); + paramMap.put("url", request.getSwaggerUrl()); + NoticeModel noticeModel = NoticeModel.builder() + .context(context) + .testId(scheduleId) + .subject(Translator.get("swagger_url_scheduled_import_notification")) + .successMailTemplate("SwaggerImport") + .paramMap(paramMap) + .event(NoticeConstants.Event.EXECUTE_SUCCESSFUL) + .build(); + noticeSendService.send(NoticeConstants.Mode.SCHEDULE, noticeModel); + } return apiImport; } diff --git a/backend/src/main/java/io/metersphere/commons/constants/NoticeConstants.java b/backend/src/main/java/io/metersphere/commons/constants/NoticeConstants.java index 6371cb2ce3..31f8347919 100644 --- a/backend/src/main/java/io/metersphere/commons/constants/NoticeConstants.java +++ b/backend/src/main/java/io/metersphere/commons/constants/NoticeConstants.java @@ -7,6 +7,7 @@ public interface NoticeConstants { String TEST_PLAN_TASK = "TEST_PLAN_TASK"; String REVIEW_TASK = "REVIEW_TASK"; String DEFECT_TASK = "DEFECT_TASK"; + String SWAGGER_TASK = "SWAGGER_TASK"; } interface Mode { @@ -28,6 +29,7 @@ public interface NoticeConstants { String UPDATE = "UPDATE"; String DELETE = "DELETE"; String COMMENT = "COMMENT"; + String IMPORT = "IMPORT"; } interface RelatedUser { diff --git a/backend/src/main/java/io/metersphere/job/sechedule/SwaggerUrlImportJob.java b/backend/src/main/java/io/metersphere/job/sechedule/SwaggerUrlImportJob.java index feb7430039..07319aaa74 100644 --- a/backend/src/main/java/io/metersphere/job/sechedule/SwaggerUrlImportJob.java +++ b/backend/src/main/java/io/metersphere/job/sechedule/SwaggerUrlImportJob.java @@ -2,6 +2,7 @@ package io.metersphere.job.sechedule; import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.service.ApiDefinitionService; +import io.metersphere.base.domain.Schedule; import io.metersphere.base.domain.SwaggerUrlProject; import io.metersphere.commons.constants.ScheduleGroup; import io.metersphere.commons.utils.CommonBeanFactory; @@ -30,6 +31,7 @@ public class SwaggerUrlImportJob extends MsScheduleJob { request.setUserId(jobDataMap.getString("userId")); request.setType("schedule"); request.setUserId(jobDataMap.getString("userId")); + request.setResourceId(resourceId); apiDefinitionService.apiTestImport(null, request); } diff --git a/backend/src/main/java/io/metersphere/service/ScheduleService.java b/backend/src/main/java/io/metersphere/service/ScheduleService.java index b21a8e463b..4bbb8cf056 100644 --- a/backend/src/main/java/io/metersphere/service/ScheduleService.java +++ b/backend/src/main/java/io/metersphere/service/ScheduleService.java @@ -289,10 +289,22 @@ public class ScheduleService { } this.editSchedule(request); - this.addOrUpdateCronJob(request,jobKey ,triggerKey , clazz); + this.addOrUpdateCronJob(request, jobKey, triggerKey, clazz); } public Object getCurrentlyExecutingJobs() { return scheduleManager.getCurrentlyExecutingJobs(); } + + public String getScheduleInfo(String id) { + ScheduleExample schedule = new ScheduleExample(); + schedule.createCriteria().andResourceIdEqualTo(id); + List list = scheduleMapper.selectByExample(schedule); + if (list.size() > 0) { + return list.get(0).getKey(); + } else { + return ""; + } + + } } diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java index 6ba46ea879..1b7e68bab1 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java @@ -904,7 +904,7 @@ public class TestPlanReportService { } } if (failurCaseObject.containsKey("scenarioTestCases") && failurCaseObject.getJSONArray("scenarioTestCases").size() >= 0) { - JSONArray array = failurCaseObject.getJSONArray("scenarioTestCases"); + JSONArray array = failurCaseObject.getJSONArray("scenarioTestCases"); if (array.size() > 0) { status = TestPlanReportStatus.FAILED.name(); return status; diff --git a/backend/src/main/resources/i18n/messages_en_US.properties b/backend/src/main/resources/i18n/messages_en_US.properties index b9d494227d..acd7730e4c 100644 --- a/backend/src/main/resources/i18n/messages_en_US.properties +++ b/backend/src/main/resources/i18n/messages_en_US.properties @@ -196,6 +196,7 @@ import_xmind_count_error=The number of use cases imported into the mind map cann import_xmind_not_found=Test case not found license_valid_license_error=Authorization authentication failed test_review_task_notice=Test review task notice +swagger_url_scheduled_import_notification=SwaggerUrl Scheduled import notification test_track.length_less_than=The title is too long, the length must be less than # check owner check_owner_project=The current user does not have permission to operate this project diff --git a/backend/src/main/resources/i18n/messages_zh_CN.properties b/backend/src/main/resources/i18n/messages_zh_CN.properties index daaa25d2cf..d53fb7dc49 100644 --- a/backend/src/main/resources/i18n/messages_zh_CN.properties +++ b/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -196,6 +196,7 @@ import_xmind_count_error=思维导图导入用例数量不能超过 500 条 license_valid_license_error=授权认证失败 import_xmind_not_found=未找到测试用例 test_review_task_notice=测试评审任务通知 +swagger_url_scheduled_import_notification=swagger_url定时导入通知 test_track.length_less_than=标题过长,字数必须小于 # check owner check_owner_project=当前用户没有操作此项目的权限 diff --git a/backend/src/main/resources/i18n/messages_zh_TW.properties b/backend/src/main/resources/i18n/messages_zh_TW.properties index b35f5bf614..3d4363a30c 100644 --- a/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -197,6 +197,7 @@ license_valid_license_code=授權碼已經存在 import_xmind_count_error=思維導圖導入用例數量不能超過 500 條 import_xmind_not_found=未找到测试用例 test_review_task_notice=測試評審任務通知 +swagger_url_scheduled_import_notification=swagger_url定時導入通知 test_track.length_less_than=標題過長,字數必須小於 # check owner check_owner_project=當前用戶沒有操作此項目的權限 diff --git a/backend/src/main/resources/mail/SwaggerImport.html b/backend/src/main/resources/mail/SwaggerImport.html new file mode 100644 index 0000000000..f16b6b3659 --- /dev/null +++ b/backend/src/main/resources/mail/SwaggerImport.html @@ -0,0 +1,15 @@ + + + + + MeterSphere + + +
+

+ ${url}
+ 导入成功! +

+
+ + \ No newline at end of file diff --git a/backend/src/main/resources/mail/SwaggerImportFaild.html b/backend/src/main/resources/mail/SwaggerImportFaild.html new file mode 100644 index 0000000000..8ba37f481b --- /dev/null +++ b/backend/src/main/resources/mail/SwaggerImportFaild.html @@ -0,0 +1,15 @@ + + + + + MeterSphere + + +
+

+ ${url}
+ 导入失败! +

+
+ + \ No newline at end of file diff --git a/frontend/src/business/components/api/definition/components/import/ApiSchedule.vue b/frontend/src/business/components/api/definition/components/import/ApiSchedule.vue index 87739073bc..09aefde90d 100644 --- a/frontend/src/business/components/api/definition/components/import/ApiSchedule.vue +++ b/frontend/src/business/components/api/definition/components/import/ApiSchedule.vue @@ -43,11 +43,25 @@
- {{$t('commons.add')}} -
- {{$t('commons.clear')}} - {{$t('commons.update')}} -
+ + + + {{ $t('schedule.task_notification') }} + + + + + {{ $t('commons.add') }} + +
+ + {{ $t('commons.clear') }} + + {{ $t('commons.update') }} + +
+
+
@@ -62,6 +76,17 @@ + + + + + + @@ -72,11 +97,17 @@ import SwaggerTaskList from "@/business/components/api/definition/components/imp import CrontabResult from "@/business/components/common/cron/CrontabResult"; import Crontab from "@/business/components/common/cron/Crontab"; import {cronValidate} from "@/common/js/cron"; -import {getCurrentProjectID, getCurrentUser, getCurrentWorkspaceId} from "@/common/js/utils"; +import {getCurrentOrganizationId, getCurrentProjectID, getCurrentUser, getCurrentWorkspaceId} from "@/common/js/utils"; import SelectTree from "@/business/components/common/select-tree/SelectTree"; +import ScheduleTaskNotification from "@/business/components/settings/organization/components/ScheduleTaskNotification"; +import SwaggerTaskNotification from "@/business/components/api/definition/components/import/SwaggerTaskNotification"; + export default { name: "ApiSchedule", - components: {SelectTree, MsFormDivider,SwaggerTaskList, CrontabResult, Crontab}, + components: { + SwaggerTaskNotification, + ScheduleTaskNotification, SelectTree, MsFormDivider, SwaggerTaskList, CrontabResult, Crontab + }, props: { customValidate: { type: Function, @@ -116,6 +147,8 @@ export default { schedule: { value: "", }, + scheduleReceiverOptions: [], + dialogVisible: false, showCron: false, activeName: 'first', swaggerUrl: String, @@ -153,6 +186,25 @@ export default { }, methods: { + openSchedule() { + if (this.formData.id !== null && this.formData.id !== undefined) { + this.dialogVisible = true; + this.initUserList(); + } else { + this.$warning("请先选择您要添加通知的定时任务"); + } + + }, + + initUserList() { + let param = { + name: '', + organizationId: getCurrentOrganizationId() + }; + this.result = this.$post('user/org/member/list/all', param, response => { + this.scheduleReceiverOptions = response.data; + }); + }, currentUser: () => { return getCurrentUser(); }, diff --git a/frontend/src/business/components/api/definition/components/import/SwaggerTaskNotification.vue b/frontend/src/business/components/api/definition/components/import/SwaggerTaskNotification.vue new file mode 100644 index 0000000000..04fe1576b8 --- /dev/null +++ b/frontend/src/business/components/api/definition/components/import/SwaggerTaskNotification.vue @@ -0,0 +1,313 @@ + + + + + +