feat(消息通知): 接口自动变更-消息提醒

--user=郭雨琦
--story=1008912
https://www.tapd.cn/55049933/prong/stories/view/1155049933001008912
This commit is contained in:
guoyuqi 2022-07-20 14:45:33 +08:00 committed by xiaomeinvG
parent b5bb9f7452
commit 6a87a14ff7
8 changed files with 119 additions and 4 deletions

View File

@ -110,7 +110,7 @@ public class ApiDefinitionController {
@PostMapping(value = "/update", consumes = {"multipart/form-data"}) @PostMapping(value = "/update", consumes = {"multipart/form-data"})
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ_EDIT_API) @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) @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<MultipartFile> bodyFiles) { public ApiDefinitionResult update(@RequestPart("request") SaveApiDefinitionRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {
checkPermissionService.checkProjectOwner(request.getProjectId()); checkPermissionService.checkProjectOwner(request.getProjectId());
return apiDefinitionService.update(request, bodyFiles); return apiDefinitionService.update(request, bodyFiles);

View File

@ -74,4 +74,13 @@ public class SaveApiDefinitionRequest {
//同步的内容 //同步的内容
private String triggerUpdate; private String triggerUpdate;
//是否发送特殊通知
private Boolean sendSpecialMessage;
//发送信息给case创建人
private Boolean caseCreator;
//发送信息给场景创建人
private Boolean scenarioCreator;
} }

View File

@ -159,6 +159,10 @@ public class ApiDefinitionService {
@Lazy @Lazy
@Resource @Resource
private ProjectService projectService; private ProjectService projectService;
@Resource
private ApiScenarioReferenceIdMapper apiScenarioReferenceIdMapper;
@Resource
private ApiScenarioMapper apiScenarioMapper;
private ThreadLocal<Long> currentApiOrder = new ThreadLocal<>(); private ThreadLocal<Long> currentApiOrder = new ThreadLocal<>();
private ThreadLocal<Long> currentApiCaseOrder = new ThreadLocal<>(); private ThreadLocal<Long> currentApiCaseOrder = new ThreadLocal<>();
@ -374,7 +378,6 @@ public class ApiDefinitionService {
if (apiDefinitionSyncService != null) { if (apiDefinitionSyncService != null) {
apiDefinitionSyncService.syncApi(request); apiDefinitionSyncService.syncApi(request);
} }
} }
ApiDefinitionWithBLOBs returnModel = updateTest(request); ApiDefinitionWithBLOBs returnModel = updateTest(request);
@ -390,9 +393,64 @@ public class ApiDefinitionService {
MockConfigService mockConfigService = CommonBeanFactory.getBean(MockConfigService.class); MockConfigService mockConfigService = CommonBeanFactory.getBean(MockConfigService.class);
mockConfigService.updateMockReturnMsgByApi(returnModel); mockConfigService.updateMockReturnMsgByApi(returnModel);
FileUtils.createBodyFiles(request.getRequest().getId(), bodyFiles); FileUtils.createBodyFiles(request.getRequest().getId(), bodyFiles);
// 发送通知
String context = SessionUtils.getUserId() + "更新了接口定义:" + returnModel.getName();
Map<String, Object> 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<String> 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()); return getById(returnModel.getId());
} }
private void getReceivers(SaveApiDefinitionRequest request, ApiDefinitionWithBLOBs returnModel, List<String> specialReceivers) {
if (request.getSendSpecialMessage() != null && request.getSendSpecialMessage()) {
if (request.getCaseCreator() != null && request.getCaseCreator()) {
ApiTestCaseExample apiTestCaseExample = new ApiTestCaseExample();
apiTestCaseExample.createCriteria().andApiDefinitionIdEqualTo(returnModel.getId());
List<ApiTestCase> 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<ApiScenarioReferenceId> apiScenarioReferenceIds = apiScenarioReferenceIdMapper.selectByExample(apiScenarioReferenceIdExample);
if (CollectionUtils.isNotEmpty(apiScenarioReferenceIds)) {
List<String> scenarioIds = apiScenarioReferenceIds.stream().map(ApiScenarioReferenceId::getApiScenarioId).collect(Collectors.toList());
ApiScenarioExample apiScenarioExample = new ApiScenarioExample();
apiScenarioExample.createCriteria().andIdIn(scenarioIds);
List<ApiScenario> apiScenarios = apiScenarioMapper.selectByExample(apiScenarioExample);
if (CollectionUtils.isNotEmpty(apiScenarios)) {
for (ApiScenario apiScenario : apiScenarios) {
specialReceivers.add(apiScenario.getCreateUser());
}
}
}
}
}
}
public void checkQuota(String projectId) { public void checkQuota(String projectId) {
QuotaService quotaService = CommonBeanFactory.getBean(QuotaService.class); QuotaService quotaService = CommonBeanFactory.getBean(QuotaService.class);
if (quotaService != null) { if (quotaService != null) {

View File

@ -76,6 +76,17 @@ public abstract class AbstractNoticeSender implements NoticeSender {
// 处理 userIds 中包含的特殊值 // 处理 userIds 中包含的特殊值
noticeModel.setReceivers(getRealUserIds(messageDetail, noticeModel, messageDetail.getEvent())); 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())) { if (StringUtils.isNotBlank(messageDetail.getTemplate())) {

View File

@ -191,8 +191,23 @@
<span>{{ $t('workstation.batch_sync_api_tips') }}</span> <span>{{ $t('workstation.batch_sync_api_tips') }}</span>
</el-row> </el-row>
<span v-if="syncCases">{{ $t('workstation.sync') + $t('commons.setting') }}</span><br/> <span v-if="syncCases">{{ $t('workstation.sync') + $t('commons.setting') }}</span><br/>
<el-row style="margin-bottom: 10px;box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)">
<sync-settings v-if="syncCases" ref="synSetting"></sync-settings> <sync-settings v-if="syncCases" ref="synSetting"></sync-settings>
</el-row>
<el-row style="margin-bottom: 10px;box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)">
<div class="timeClass">
<span>{{ $t('api_test.definition.change_notification') }}</span>
<el-switch v-model="specialReceivers"></el-switch>
</div>
<span>{{ $t('api_test.definition.recipient_tips') }}</span>
<el-row v-if="specialReceivers">
<el-col :span="4">{{ $t('api_test.definition.recipient') + ":" }}</el-col>
<el-col :span="20" style="color: #783887">
<el-checkbox v-model="caseCreator">{{ 'CASE' + $t('api_test.creator') }}</el-checkbox>
<el-checkbox v-model="scenarioCreator">{{ $t('commons.scenario') + $t('api_test.creator') }}</el-checkbox>
</el-col>
</el-row>
</el-row>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="batchSyncApiVisible = false"> </el-button> <el-button @click="batchSyncApiVisible = false"> </el-button>
<el-button type="primary" @click="batchSync()"> </el-button> <el-button type="primary" @click="batchSync()"> </el-button>
@ -290,6 +305,10 @@ export default {
createNewVersionVisible: false, createNewVersionVisible: false,
batchSyncApiVisible: false, batchSyncApiVisible: false,
syncCases: true, syncCases: true,
specialReceivers: false,
caseCreator: false,
scenarioCreator: false
}; };
}, },
props: {moduleOptions: {}, request: {}, response: {}, basisData: {}, syncTabs: Array, projectId: String}, props: {moduleOptions: {}, request: {}, response: {}, basisData: {}, syncTabs: Array, projectId: String},
@ -516,6 +535,15 @@ export default {
let fromData = this.$refs.synSetting.fromData; let fromData = this.$refs.synSetting.fromData;
this.httpForm.triggerUpdate = JSON.stringify(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); this.$emit('saveApi', this.httpForm);
} }
}, },

View File

@ -1243,6 +1243,9 @@ export default {
check_select: "Please check the API", check_select: "Please check the API",
api_project: "Project", api_project: "Project",
one_click_sync: "One-click sync", 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: { select_comp: {
no_data: "No Data", no_data: "No Data",
add_data: "Add Data" add_data: "Add Data"

View File

@ -1252,6 +1252,9 @@ export default {
check_select: "请勾选接口", check_select: "请勾选接口",
api_project: "所属项目", api_project: "所属项目",
one_click_sync: "一键同步", one_click_sync: "一键同步",
change_notification: "变更通知",
recipient: "接受人",
recipient_tips: "当API发生变化时关联的CASE创建人、自动化场景创建人会收到站内消息",
select_comp: { select_comp: {
no_data: "无数据", no_data: "无数据",
add_data: "去添加" add_data: "去添加"

View File

@ -1249,6 +1249,9 @@ export default {
check_select: "請勾選接口", check_select: "請勾選接口",
api_project: "所屬項目", api_project: "所屬項目",
one_click_sync: "一鍵同步", one_click_sync: "一鍵同步",
change_notification: "變更通知",
recipient: "接收人",
recipient_tips: "當API發生變化時關聯的CASE創建人、自動化場景創建人會收到站內消息",
select_comp: { select_comp: {
no_data: "無數據", no_data: "無數據",
add_data: "去添加" add_data: "去添加"