From 6a87a14ff7981214a36230d7dc6aed501f40bcfd Mon Sep 17 00:00:00 2001 From: guoyuqi Date: Wed, 20 Jul 2022 14:45:33 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=B6=88=E6=81=AF=E9=80=9A=E7=9F=A5):=20?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E8=87=AA=E5=8A=A8=E5=8F=98=E6=9B=B4-?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --user=郭雨琦 --story=1008912 https://www.tapd.cn/55049933/prong/stories/view/1155049933001008912 --- .../controller/ApiDefinitionController.java | 2 +- .../definition/SaveApiDefinitionRequest.java | 9 +++ .../api/service/ApiDefinitionService.java | 60 ++++++++++++++++++- .../notice/sender/AbstractNoticeSender.java | 11 ++++ .../complete/EditCompleteHTTPApi.vue | 32 +++++++++- frontend/src/i18n/en-US.js | 3 + frontend/src/i18n/zh-CN.js | 3 + frontend/src/i18n/zh-TW.js | 3 + 8 files changed, 119 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java b/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java index d4ecb0d87d..b1bb26169f 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java @@ -110,7 +110,7 @@ public class ApiDefinitionController { @PostMapping(value = "/update", consumes = {"multipart/form-data"}) @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ_EDIT_API) @MsAuditLog(module = OperLogModule.API_DEFINITION, type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#request.id)", title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = ApiDefinitionService.class) - @SendNotice(taskType = NoticeConstants.TaskType.API_DEFINITION_TASK, event = NoticeConstants.Event.UPDATE, subject = "接口定义通知") + // @SendNotice(taskType = NoticeConstants.TaskType.API_DEFINITION_TASK, event = NoticeConstants.Event.UPDATE, subject = "接口定义通知") public ApiDefinitionResult update(@RequestPart("request") SaveApiDefinitionRequest request, @RequestPart(value = "files", required = false) List bodyFiles) { checkPermissionService.checkProjectOwner(request.getProjectId()); return apiDefinitionService.update(request, bodyFiles); diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/SaveApiDefinitionRequest.java b/backend/src/main/java/io/metersphere/api/dto/definition/SaveApiDefinitionRequest.java index 0d5054b75b..8ad4148e8d 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/SaveApiDefinitionRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/SaveApiDefinitionRequest.java @@ -74,4 +74,13 @@ public class SaveApiDefinitionRequest { //同步的内容 private String triggerUpdate; + //是否发送特殊通知 + private Boolean sendSpecialMessage; + + //发送信息给case创建人 + private Boolean caseCreator; + + //发送信息给场景创建人 + private Boolean scenarioCreator; + } 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 101be3ea63..eed6b1d6b8 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -159,6 +159,10 @@ public class ApiDefinitionService { @Lazy @Resource private ProjectService projectService; + @Resource + private ApiScenarioReferenceIdMapper apiScenarioReferenceIdMapper; + @Resource + private ApiScenarioMapper apiScenarioMapper; private ThreadLocal currentApiOrder = new ThreadLocal<>(); private ThreadLocal currentApiCaseOrder = new ThreadLocal<>(); @@ -374,7 +378,6 @@ public class ApiDefinitionService { if (apiDefinitionSyncService != null) { apiDefinitionSyncService.syncApi(request); } - } ApiDefinitionWithBLOBs returnModel = updateTest(request); @@ -390,9 +393,64 @@ public class ApiDefinitionService { MockConfigService mockConfigService = CommonBeanFactory.getBean(MockConfigService.class); mockConfigService.updateMockReturnMsgByApi(returnModel); FileUtils.createBodyFiles(request.getRequest().getId(), bodyFiles); + // 发送通知 + String context = SessionUtils.getUserId() + "更新了接口定义:" + returnModel.getName(); + Map paramMap = new HashMap<>(); + paramMap.put("projectId", request.getProjectId()); + paramMap.put("operator", SessionUtils.getUserId()); + paramMap.put("id", returnModel.getId()); + paramMap.put("name", returnModel.getName()); + paramMap.put("createUser", returnModel.getCreateUser()); + paramMap.put("userId", returnModel.getUserId()); + List specialReceivers = new ArrayList<>(); + this.getReceivers(request, returnModel, specialReceivers); + if (request.getSendSpecialMessage() != null && request.getSendSpecialMessage()) { + paramMap.put("specialReceivers", JSON.toJSONString(specialReceivers)); + paramMap.put("apiSpecialType", "API_SPECIAL"); + } + NoticeModel noticeModel = NoticeModel.builder() + .operator(SessionUtils.getUserId()) + .context(context) + .testId(returnModel.getId()) + .subject("接口更新通知") + .paramMap(paramMap) + .event(NoticeConstants.Event.UPDATE) + .build(); + noticeSendService.send(NoticeConstants.TaskType.API_DEFINITION_TASK, noticeModel); return getById(returnModel.getId()); } + private void getReceivers(SaveApiDefinitionRequest request, ApiDefinitionWithBLOBs returnModel, List specialReceivers) { + if (request.getSendSpecialMessage() != null && request.getSendSpecialMessage()) { + if (request.getCaseCreator() != null && request.getCaseCreator()) { + ApiTestCaseExample apiTestCaseExample = new ApiTestCaseExample(); + apiTestCaseExample.createCriteria().andApiDefinitionIdEqualTo(returnModel.getId()); + List apiTestCases = apiTestCaseMapper.selectByExample(apiTestCaseExample); + if (CollectionUtils.isNotEmpty(apiTestCases)) { + for (ApiTestCase apiTestCase : apiTestCases) { + specialReceivers.add(apiTestCase.getCreateUserId()); + } + } + } + if (request.getScenarioCreator() != null && request.getScenarioCreator()) { + ApiScenarioReferenceIdExample apiScenarioReferenceIdExample = new ApiScenarioReferenceIdExample(); + apiScenarioReferenceIdExample.createCriteria().andDataTypeEqualTo("API").andReferenceIdEqualTo(returnModel.getId()); + List apiScenarioReferenceIds = apiScenarioReferenceIdMapper.selectByExample(apiScenarioReferenceIdExample); + if (CollectionUtils.isNotEmpty(apiScenarioReferenceIds)) { + List scenarioIds = apiScenarioReferenceIds.stream().map(ApiScenarioReferenceId::getApiScenarioId).collect(Collectors.toList()); + ApiScenarioExample apiScenarioExample = new ApiScenarioExample(); + apiScenarioExample.createCriteria().andIdIn(scenarioIds); + List apiScenarios = apiScenarioMapper.selectByExample(apiScenarioExample); + if (CollectionUtils.isNotEmpty(apiScenarios)) { + for (ApiScenario apiScenario : apiScenarios) { + specialReceivers.add(apiScenario.getCreateUser()); + } + } + } + } + } + } + public void checkQuota(String projectId) { QuotaService quotaService = CommonBeanFactory.getBean(QuotaService.class); if (quotaService != null) { diff --git a/backend/src/main/java/io/metersphere/notice/sender/AbstractNoticeSender.java b/backend/src/main/java/io/metersphere/notice/sender/AbstractNoticeSender.java index 79a318d158..216c9e40ca 100644 --- a/backend/src/main/java/io/metersphere/notice/sender/AbstractNoticeSender.java +++ b/backend/src/main/java/io/metersphere/notice/sender/AbstractNoticeSender.java @@ -76,6 +76,17 @@ public abstract class AbstractNoticeSender implements NoticeSender { // 处理 userIds 中包含的特殊值 noticeModel.setReceivers(getRealUserIds(messageDetail, noticeModel, messageDetail.getEvent())); + //apiReceiver特殊处理 + String apiSpecialType = (String) noticeModel.getParamMap().get("apiSpecialType"); + if (apiSpecialType != null && apiSpecialType.equals("API_SPECIAL")) { + String specialReceivers = (String) noticeModel.getParamMap().get("specialReceivers"); + JSONArray array = JSON.parseArray(specialReceivers); + if (CollectionUtils.isNotEmpty(array)) { + for (Object o : array) { + noticeModel.getReceivers().add(new Receiver(o.toString(), NotificationConstants.Type.MENTIONED_ME.name())); + } + } + } // 如果配置了模版就直接使用模版 if (StringUtils.isNotBlank(messageDetail.getTemplate())) { diff --git a/frontend/src/business/components/api/definition/components/complete/EditCompleteHTTPApi.vue b/frontend/src/business/components/api/definition/components/complete/EditCompleteHTTPApi.vue index 1d65866536..cac9ba05fe 100644 --- a/frontend/src/business/components/api/definition/components/complete/EditCompleteHTTPApi.vue +++ b/frontend/src/business/components/api/definition/components/complete/EditCompleteHTTPApi.vue @@ -191,8 +191,23 @@ {{ $t('workstation.batch_sync_api_tips') }} {{ $t('workstation.sync') + $t('commons.setting') }}
- - + + + + +
+ {{ $t('api_test.definition.change_notification') }} + +
+ {{ $t('api_test.definition.recipient_tips') }} + + {{ $t('api_test.definition.recipient') + ":" }} + + {{ 'CASE' + $t('api_test.creator') }} + {{ $t('commons.scenario') + $t('api_test.creator') }} + + +
取 消 确 定 @@ -290,6 +305,10 @@ export default { createNewVersionVisible: false, batchSyncApiVisible: false, syncCases: true, + specialReceivers: false, + caseCreator: false, + scenarioCreator: false + }; }, props: {moduleOptions: {}, request: {}, response: {}, basisData: {}, syncTabs: Array, projectId: String}, @@ -516,6 +535,15 @@ export default { let fromData = this.$refs.synSetting.fromData; this.httpForm.triggerUpdate = JSON.stringify(fromData); } + if (this.specialReceivers) { + this.httpForm.sendSpecialMessage = this.specialReceivers; + } + if (this.caseCreator) { + this.httpForm.caseCreator = this.caseCreator; + } + if (this.scenarioCreator) { + this.httpForm.scenarioCreator = this.scenarioCreator; + } this.$emit('saveApi', this.httpForm); } }, diff --git a/frontend/src/i18n/en-US.js b/frontend/src/i18n/en-US.js index a4507ea469..4fff9e5ece 100644 --- a/frontend/src/i18n/en-US.js +++ b/frontend/src/i18n/en-US.js @@ -1243,6 +1243,9 @@ export default { check_select: "Please check the API", api_project: "Project", one_click_sync: "One-click sync", + change_notification: "Change Notification", + recipient: "Recipient", + recipient_tips: "When the API changes, the associated CASE creator and automation scene creator will receive in-site messages", select_comp: { no_data: "No Data", add_data: "Add Data" diff --git a/frontend/src/i18n/zh-CN.js b/frontend/src/i18n/zh-CN.js index 2676af81a3..48085001cf 100644 --- a/frontend/src/i18n/zh-CN.js +++ b/frontend/src/i18n/zh-CN.js @@ -1252,6 +1252,9 @@ export default { check_select: "请勾选接口", api_project: "所属项目", one_click_sync: "一键同步", + change_notification: "变更通知", + recipient: "接受人", + recipient_tips: "当API发生变化时,关联的CASE创建人、自动化场景创建人会收到站内消息", select_comp: { no_data: "无数据", add_data: "去添加" diff --git a/frontend/src/i18n/zh-TW.js b/frontend/src/i18n/zh-TW.js index d4831cf661..059a02d03c 100644 --- a/frontend/src/i18n/zh-TW.js +++ b/frontend/src/i18n/zh-TW.js @@ -1249,6 +1249,9 @@ export default { check_select: "請勾選接口", api_project: "所屬項目", one_click_sync: "一鍵同步", + change_notification: "變更通知", + recipient: "接收人", + recipient_tips: "當API發生變化時,關聯的CASE創建人、自動化場景創建人會收到站內消息", select_comp: { no_data: "無數據", add_data: "去添加"