feat(接口自动化): 完善回收站功能

This commit is contained in:
fit2-zhao 2020-12-09 19:02:26 +08:00
parent 0660600aab
commit 1f59d12f7b
5 changed files with 58 additions and 52 deletions

View File

@ -22,7 +22,6 @@ import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode; import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ReportTriggerMode; import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import io.metersphere.track.dto.TestPlanDTO; import io.metersphere.track.dto.TestPlanDTO;
@ -34,13 +33,11 @@ import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree; import org.apache.jorphan.collections.ListedHashTree;
import org.aspectj.util.FileUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.*;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -51,6 +48,8 @@ public class ApiAutomationService {
@Resource @Resource
private ApiScenarioMapper apiScenarioMapper; private ApiScenarioMapper apiScenarioMapper;
@Resource @Resource
private ApiDefinitionService apiDefinitionService;
@Resource
private ExtApiScenarioMapper extApiScenarioMapper; private ExtApiScenarioMapper extApiScenarioMapper;
@Resource @Resource
private ApiTagMapper apiTagMapper; private ApiTagMapper apiTagMapper;
@ -126,13 +125,13 @@ public class ApiAutomationService {
apiScenarioMapper.insert(scenario); apiScenarioMapper.insert(scenario);
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds()); List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
createBodyFiles(bodyUploadIds, bodyFiles); apiDefinitionService.createBodyFiles(bodyUploadIds, bodyFiles);
} }
public void update(SaveApiScenarioRequest request, List<MultipartFile> bodyFiles) { public void update(SaveApiScenarioRequest request, List<MultipartFile> bodyFiles) {
checkNameExist(request); checkNameExist(request);
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds()); List<String> bodyUploadIds = request.getBodyUploadIds();
createBodyFiles(bodyUploadIds, bodyFiles); apiDefinitionService.createBodyFiles(bodyUploadIds, bodyFiles);
final ApiScenario scenario = new ApiScenario(); final ApiScenario scenario = new ApiScenario();
scenario.setId(request.getId()); scenario.setId(request.getId());
@ -177,7 +176,7 @@ public class ApiAutomationService {
private void checkNameExist(SaveApiScenarioRequest request) { private void checkNameExist(SaveApiScenarioRequest request) {
ApiScenarioExample example = new ApiScenarioExample(); ApiScenarioExample example = new ApiScenarioExample();
example.createCriteria().andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId()); example.createCriteria().andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()).andStatusNotEqualTo("Trash").andIdNotEqualTo(request.getId());
if (apiScenarioMapper.countByExample(example) > 0) { if (apiScenarioMapper.countByExample(example) > 0) {
MSException.throwException(Translator.get("automation_name_already_exists")); MSException.throwException(Translator.get("automation_name_already_exists"));
} }
@ -194,26 +193,6 @@ public class ApiAutomationService {
return new ArrayList<>(); return new ArrayList<>();
} }
private void createBodyFiles(List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
if (!bodyUploadIds.isEmpty() && !bodyFiles.isEmpty()) {
File testDir = new File(BODY_FILE_DIR);
if (!testDir.exists()) {
testDir.mkdirs();
}
for (int i = 0; i < bodyUploadIds.size(); i++) {
MultipartFile item = bodyFiles.get(i);
File file = new File(BODY_FILE_DIR + "/" + bodyUploadIds.get(i) + "_" + item.getOriginalFilename());
try (InputStream in = item.getInputStream(); OutputStream out = new FileOutputStream(file)) {
file.createNewFile();
FileUtil.copyStream(in, out);
} catch (IOException e) {
LogUtil.error(e);
MSException.throwException(Translator.get("upload_fail"));
}
}
}
}
public void deleteTag(String id) { public void deleteTag(String id) {
List<ApiScenario> list = extApiScenarioMapper.selectByTagId(id); List<ApiScenario> list = extApiScenarioMapper.selectByTagId(id);
if (!list.isEmpty()) { if (!list.isEmpty()) {
@ -297,7 +276,7 @@ public class ApiAutomationService {
*/ */
public String run(RunDefinitionRequest request, List<MultipartFile> bodyFiles) { public String run(RunDefinitionRequest request, List<MultipartFile> bodyFiles) {
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds()); List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
createBodyFiles(bodyUploadIds, bodyFiles); apiDefinitionService.createBodyFiles(bodyUploadIds, bodyFiles);
EnvironmentConfig envConfig = null; EnvironmentConfig envConfig = null;
if (request.getEnvironmentId() != null) { if (request.getEnvironmentId() != null) {
ApiTestEnvironmentWithBLOBs environment = environmentService.get(request.getEnvironmentId()); ApiTestEnvironmentWithBLOBs environment = environmentService.get(request.getEnvironmentId());

View File

@ -25,7 +25,7 @@ import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import io.metersphere.service.FileService; import io.metersphere.service.FileService;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactory;
@ -33,13 +33,15 @@ import org.apache.jorphan.collections.HashTree;
import org.aspectj.util.FileUtil; import org.aspectj.util.FileUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import sun.security.util.Cache; import sun.security.util.Cache;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.*; import java.io.*;
import java.util.*; import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -103,15 +105,17 @@ public class ApiDefinitionService {
} }
public void update(SaveApiDefinitionRequest request, List<MultipartFile> bodyFiles) { public void update(SaveApiDefinitionRequest request, List<MultipartFile> bodyFiles) {
if (request.getRequest() != null) {
deleteFileByTestId(request.getRequest().getId()); deleteFileByTestId(request.getRequest().getId());
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds()); }
List<String> bodyUploadIds = request.getBodyUploadIds();
request.setBodyUploadIds(null); request.setBodyUploadIds(null);
updateTest(request); updateTest(request);
createBodyFiles(bodyUploadIds, bodyFiles); createBodyFiles(bodyUploadIds, bodyFiles);
} }
private void createBodyFiles(List<String> bodyUploadIds, List<MultipartFile> bodyFiles) { public void createBodyFiles(List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
if (bodyUploadIds.size() > 0) { if (CollectionUtils.isNotEmpty(bodyUploadIds) && CollectionUtils.isNotEmpty(bodyFiles)) {
File testDir = new File(BODY_FILE_DIR); File testDir = new File(BODY_FILE_DIR);
if (!testDir.exists()) { if (!testDir.exists()) {
testDir.mkdirs(); testDir.mkdirs();
@ -139,10 +143,9 @@ public class ApiDefinitionService {
} }
public void deleteBatch(List<String> apiIds) { public void deleteBatch(List<String> apiIds) {
// 简单处理后续优化 ApiDefinitionExample example = new ApiDefinitionExample();
apiIds.forEach(item -> { example.createCriteria().andIdIn(apiIds);
delete(item); apiDefinitionMapper.deleteByExample(example);
});
} }
public void removeToGc(List<String> apiIds) { public void removeToGc(List<String> apiIds) {
@ -160,14 +163,14 @@ public class ApiDefinitionService {
private void checkNameExist(SaveApiDefinitionRequest request) { private void checkNameExist(SaveApiDefinitionRequest request) {
ApiDefinitionExample example = new ApiDefinitionExample(); ApiDefinitionExample example = new ApiDefinitionExample();
if (request.getProtocol().equals(RequestType.HTTP)) { if (request.getProtocol().equals(RequestType.HTTP)) {
example.createCriteria().andMethodEqualTo(request.getMethod()) example.createCriteria().andMethodEqualTo(request.getMethod()).andStatusNotEqualTo("Trash")
.andProtocolEqualTo(request.getProtocol()).andPathEqualTo(request.getPath()) .andProtocolEqualTo(request.getProtocol()).andPathEqualTo(request.getPath())
.andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId()); .andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId());
if (apiDefinitionMapper.countByExample(example) > 0) { if (apiDefinitionMapper.countByExample(example) > 0) {
MSException.throwException(Translator.get("api_definition_url_not_repeating")); MSException.throwException(Translator.get("api_definition_url_not_repeating"));
} }
} else { } else {
example.createCriteria().andProtocolEqualTo(request.getProtocol()) example.createCriteria().andProtocolEqualTo(request.getProtocol()).andStatusNotEqualTo("Trash")
.andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()) .andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId())
.andIdNotEqualTo(request.getId()); .andIdNotEqualTo(request.getId());
if (apiDefinitionMapper.countByExample(example) > 0) { if (apiDefinitionMapper.countByExample(example) > 0) {
@ -176,7 +179,6 @@ public class ApiDefinitionService {
} }
} }
private ApiDefinition updateTest(SaveApiDefinitionRequest request) { private ApiDefinition updateTest(SaveApiDefinitionRequest request) {
checkNameExist(request); checkNameExist(request);
final ApiDefinitionWithBLOBs test = new ApiDefinitionWithBLOBs(); final ApiDefinitionWithBLOBs test = new ApiDefinitionWithBLOBs();

View File

@ -47,11 +47,16 @@
show-overflow-tooltip/> show-overflow-tooltip/>
<el-table-column :label="$t('commons.operating')" width="200px" v-if="!referenced"> <el-table-column :label="$t('commons.operating')" width="200px" v-if="!referenced">
<template v-slot:default="{row}"> <template v-slot:default="{row}">
<div v-if="currentModule!=undefined && currentModule.id === 'gc'">
<el-button type="text" @click="reductionApi(row)">恢复</el-button>
</div>
<div v-else>
<el-button type="text" @click="edit(row)">{{ $t('api_test.automation.edit') }}</el-button> <el-button type="text" @click="edit(row)">{{ $t('api_test.automation.edit') }}</el-button>
<el-button type="text" @click="execute(row)">{{ $t('api_test.automation.execute') }}</el-button> <el-button type="text" @click="execute(row)">{{ $t('api_test.automation.execute') }}</el-button>
<el-button type="text" @click="copy(row)">{{ $t('api_test.automation.copy') }}</el-button> <el-button type="text" @click="copy(row)">{{ $t('api_test.automation.copy') }}</el-button>
<el-button type="text" @click="remove(row)">{{ $t('api_test.automation.remove') }}</el-button> <el-button type="text" @click="remove(row)">{{ $t('api_test.automation.remove') }}</el-button>
<ms-scenario-extend-buttons :row="row"/> <ms-scenario-extend-buttons :row="row"/>
</div>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -202,6 +207,13 @@
edit(row) { edit(row) {
this.$emit('edit', row); this.$emit('edit', row);
}, },
reductionApi(row) {
let obj = {id: row.id, projectId: row.projectId, name: row.name, status: 'Underway'}
this.$fileUpload("/api/automation/update", null, [], obj, () => {
this.$success(this.$t('commons.save_success'));
this.search();
})
},
execute(row) { execute(row) {
this.infoDb = false; this.infoDb = false;
let url = "/api/automation/run"; let url = "/api/automation/run";

View File

@ -240,7 +240,7 @@
<el-drawer :visible.sync="apiListVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('api_test.automation.api_list_import')" :modal="false" size="90%"> <el-drawer :visible.sync="apiListVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('api_test.automation.api_list_import')" :modal="false" size="90%">
<ms-api-definition :visible="true" :currentRow="currentRow"/> <ms-api-definition :visible="true" :currentRow="currentRow"/>
<!--<el-button style="float: right;margin: 20px" type="primary" @click="copyApi('REF')">{{$t('api_test.scenario.reference')}}</el-button>--> <!--<el-button style="float: right;margin: 20px" type="primary" @click="copyApi('REF')">{{$t('api_test.scenario.reference')}}</el-button>-->
<el-button style="float: right;margin: 20px 0px 0px " type="primary" @click="copyApi('Copy')">{{ $t('commons.copy') }}</el-button> <el-button style="float: right;margin: 0px 20px 0px" type="primary" @click="copyApi('Copy')">{{ $t('commons.copy') }}</el-button>
</el-drawer> </el-drawer>
<!--自定义接口--> <!--自定义接口-->
@ -326,6 +326,7 @@
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}], userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
apiScenarioModuleId: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}], apiScenarioModuleId: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
status: [{required: true, message: this.$t('commons.please_select'), trigger: 'change'}], status: [{required: true, message: this.$t('commons.please_select'), trigger: 'change'}],
principal: [{required: true, message: this.$t('api_test.definition.request.responsible'), trigger: 'change'}],
}, },
environments: [], environments: [],
tags: [], tags: [],
@ -684,11 +685,13 @@
this.path = "/api/automation/update"; this.path = "/api/automation/update";
if (response.data.scenarioDefinition != null) { if (response.data.scenarioDefinition != null) {
let obj = JSON.parse(response.data.scenarioDefinition); let obj = JSON.parse(response.data.scenarioDefinition);
if (obj) {
this.currentEnvironmentId = obj.environmentId; this.currentEnvironmentId = obj.environmentId;
this.currentScenario.variables = obj.variables; this.currentScenario.variables = obj.variables;
this.scenarioDefinition = obj.hashTree; this.scenarioDefinition = obj.hashTree;
} }
} }
}
}) })
} }
}, },

View File

@ -77,7 +77,8 @@
<el-button type="text" @click="handleTestCase(scope.row)">用例</el-button> <el-button type="text" @click="handleTestCase(scope.row)">用例</el-button>
</div> </div>
<div v-else> <div v-else>
<el-button type="text" @click="editApi(scope.row)">编辑</el-button> <el-button type="text" @click="reductionApi(scope.row)" v-if="currentModule!=undefined && currentModule.id === 'gc'">恢复</el-button>
<el-button type="text" @click="editApi(scope.row)" v-else>编辑</el-button>
<el-button type="text" @click="handleTestCase(scope.row)">用例</el-button> <el-button type="text" @click="handleTestCase(scope.row)">用例</el-button>
<el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C">删除</el-button> <el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C">删除</el-button>
</div> </div>
@ -256,6 +257,15 @@
editApi(row) { editApi(row) {
this.$emit('editApi', row); this.$emit('editApi', row);
}, },
reductionApi(row) {
row.status = 'Underway';
row.request = null;
row.response = null;
this.$fileUpload("/api/definition/update", null, [], row, () => {
this.$success(this.$t('commons.save_success'));
this.search();
});
},
handleDeleteBatch() { handleDeleteBatch() {
if (this.currentModule != undefined && this.currentModule.id == "gc") { if (this.currentModule != undefined && this.currentModule.id == "gc") {
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "", '', { this.$alert(this.$t('api_test.definition.request.delete_confirm') + "", '', {