diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionImportParamDTO.java b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionImportParamDTO.java index 5e67f96cb6..fdeb88a619 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionImportParamDTO.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionImportParamDTO.java @@ -4,6 +4,8 @@ import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.mock.config.MockConfigImportDTO; import io.metersphere.base.domain.ApiDefinitionWithBLOBs; import io.metersphere.base.domain.ApiTestCaseWithBLOBs; +import io.metersphere.base.mapper.OperatingLogMapper; +import io.metersphere.base.mapper.OperatingLogResourceMapper; import lombok.Getter; import lombok.Setter; @@ -19,14 +21,11 @@ public class ApiDefinitionImportParamDTO { private List caseList; private List repeatList; + private String importType; + private String scheduleId; - - - - - - public ApiDefinitionImportParamDTO() { - } + private OperatingLogMapper operatingLogMapper; + private OperatingLogResourceMapper operatingLogResourceMapper; public ApiDefinitionImportParamDTO(ApiDefinitionWithBLOBs apiDefinition, ApiTestImportRequest apiTestImportRequest, List mocks, List updateList, List caseList) { this.apiDefinition = apiDefinition; diff --git a/api-test/backend/src/main/java/io/metersphere/commons/utils/ApiTestDefinitionDiffUtilImpl.java b/api-test/backend/src/main/java/io/metersphere/commons/utils/ApiTestDefinitionDiffUtilImpl.java index d1421d9c9f..a132eff23c 100644 --- a/api-test/backend/src/main/java/io/metersphere/commons/utils/ApiTestDefinitionDiffUtilImpl.java +++ b/api-test/backend/src/main/java/io/metersphere/commons/utils/ApiTestDefinitionDiffUtilImpl.java @@ -5,6 +5,7 @@ import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler; import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler; import io.metersphere.api.dto.scenario.Body; +import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.commons.constants.ElementConstants; import io.metersphere.log.utils.ApiDefinitionDiffUtil; import io.metersphere.log.utils.ReflexObjectUtil; @@ -17,6 +18,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.json.JSONObject; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -94,11 +96,12 @@ public class ApiTestDefinitionDiffUtilImpl implements ApiDefinitionDiffUtil { private static void diffHttp(MsHTTPSamplerProxy httpNew, MsHTTPSamplerProxy httpOld, JsonDiff jsonDiff, Map diffMap) { // 请求头对比 old/new - if (CollectionUtils.isNotEmpty(httpNew.getHeaders()) && CollectionUtils.isNotEmpty(httpOld.getHeaders())) { - httpNew.getHeaders().remove(httpNew.getHeaders().size() - 1); - httpOld.getHeaders().remove(httpOld.getHeaders().size() - 1); + if (CollectionUtils.isNotEmpty(httpNew.getHeaders())) { + removeSpaceName(httpNew.getHeaders()); + } + if (CollectionUtils.isNotEmpty(httpOld.getHeaders())) { + removeSpaceName(httpOld.getHeaders()); } - String headerNew = StringUtils.join(JSON_START, JSON.toJSONString(httpNew.getHeaders()), JSON_END); String headerOld = StringUtils.join(JSON_START, JSON.toJSONString(httpOld.getHeaders()), JSON_END); if (!StringUtils.equals(headerNew, headerOld)) { @@ -109,9 +112,11 @@ public class ApiTestDefinitionDiffUtilImpl implements ApiDefinitionDiffUtil { } } // 对比QUERY参数 - if (CollectionUtils.isNotEmpty(httpNew.getArguments()) && CollectionUtils.isNotEmpty(httpOld.getArguments())) { - httpNew.getArguments().remove(httpNew.getArguments().size() - 1); - httpOld.getArguments().remove(httpOld.getArguments().size() - 1); + if (CollectionUtils.isNotEmpty(httpNew.getArguments())) { + removeSpaceName(httpNew.getArguments()); + } + if (CollectionUtils.isNotEmpty(httpOld.getArguments())) { + removeSpaceName(httpOld.getArguments()); } String queryNew = StringUtils.join(JSON_START, JSON.toJSONString(httpNew.getArguments()), JSON_END); String queryOld = StringUtils.join(JSON_START, JSON.toJSONString(httpOld.getArguments()), JSON_END); @@ -123,9 +128,11 @@ public class ApiTestDefinitionDiffUtilImpl implements ApiDefinitionDiffUtil { } } // 对比REST参数 - if (CollectionUtils.isNotEmpty(httpNew.getRest()) && CollectionUtils.isNotEmpty(httpOld.getRest())) { - httpNew.getRest().remove(httpNew.getRest().size() - 1); - httpOld.getRest().remove(httpOld.getRest().size() - 1); + if (CollectionUtils.isNotEmpty(httpNew.getRest())) { + removeSpaceName(httpNew.getRest()); + } + if (CollectionUtils.isNotEmpty(httpOld.getRest())) { + removeSpaceName(httpOld.getRest()); } String restNew = StringUtils.join(JSON_START, JSON.toJSONString(httpNew.getRest()), JSON_END); String restOld = StringUtils.join(JSON_START, JSON.toJSONString(httpOld.getRest()), JSON_END); @@ -142,21 +149,23 @@ public class ApiTestDefinitionDiffUtilImpl implements ApiDefinitionDiffUtil { String bodyOld = JSON.toJSONString(httpOld.getBody()); if (!StringUtils.equals(bodyNew, bodyOld)) { String patch = jsonDiff.diff(bodyOld, bodyNew); - String diff = jsonDiff.apply(bodyNew, patch); + String diff = jsonDiff.apply(bodyOld, patch); if (StringUtils.isNotEmpty(diff)) { diffMap.put(BODY, diff); } } // 对比BODY-FORM参数 - if (CollectionUtils.isNotEmpty(httpNew.getBody().getKvs()) && CollectionUtils.isNotEmpty(httpOld.getBody().getKvs())) { - httpNew.getBody().getKvs().remove(httpNew.getBody().getKvs().size() - 1); - httpOld.getBody().getKvs().remove(httpOld.getBody().getKvs().size() - 1); + if (CollectionUtils.isNotEmpty(httpNew.getBody().getKvs())) { + removeSpaceName(httpNew.getBody().getKvs()); + } + if (CollectionUtils.isNotEmpty(httpOld.getBody().getKvs())) { + removeSpaceName(httpOld.getBody().getKvs()); } String bodyFormNew = StringUtils.join(JSON_START, JSON.toJSONString(httpNew.getBody().getKvs()), JSON_END); String bodyFormOld = StringUtils.join(JSON_START, JSON.toJSONString(httpOld.getBody().getKvs()), JSON_END); if (!StringUtils.equals(bodyFormNew, bodyFormOld)) { String patch = jsonDiff.diff(bodyFormOld, bodyFormNew); - String diff = jsonDiff.apply(bodyFormNew, patch); + String diff = jsonDiff.apply(bodyFormOld, patch); if (StringUtils.isNotEmpty(diff)) { diffMap.put(BODY_FORM, diff); } @@ -194,6 +203,16 @@ public class ApiTestDefinitionDiffUtilImpl implements ApiDefinitionDiffUtil { } } + private static void removeSpaceName(List keyValues) { + Iterator iterator = keyValues.iterator(); + while (iterator.hasNext()) { + KeyValue next = iterator.next(); + if (StringUtils.isBlank(next.getName())) { + iterator.remove(); + } + } + } + private static void diffHttpResponse(JSONObject httpNew, JSONObject httpOld, JsonDiff jsonDiff, Map diffMap) { // 请求头对比 old/new if (httpNew.get(HEADS) != null && httpOld.get(HEADS) != null) { diff --git a/api-test/backend/src/main/java/io/metersphere/service/definition/ApiDefinitionImportUtilService.java b/api-test/backend/src/main/java/io/metersphere/service/definition/ApiDefinitionImportUtilService.java index 009be99c19..2c54fd008a 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/definition/ApiDefinitionImportUtilService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/definition/ApiDefinitionImportUtilService.java @@ -8,20 +8,22 @@ import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler; import io.metersphere.api.dto.mock.config.MockConfigImportDTO; import io.metersphere.api.parse.api.ApiDefinitionImport; import io.metersphere.base.domain.*; -import io.metersphere.base.mapper.ApiDefinitionMapper; -import io.metersphere.base.mapper.ApiModuleMapper; -import io.metersphere.base.mapper.ApiTestCaseMapper; -import io.metersphere.base.mapper.ProjectMapper; +import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.ext.BaseProjectVersionMapper; import io.metersphere.base.mapper.ext.ExtApiDefinitionMapper; import io.metersphere.base.mapper.ext.ExtApiTestCaseMapper; import io.metersphere.commons.constants.*; import io.metersphere.commons.enums.ApiTestDataStatus; import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.user.SessionUser; import io.metersphere.commons.utils.*; import io.metersphere.dto.ProjectConfig; import io.metersphere.dto.UserDTO; import io.metersphere.i18n.Translator; +import io.metersphere.log.utils.ReflexObjectUtil; +import io.metersphere.log.vo.DetailColumn; +import io.metersphere.log.vo.OperatingLogDetails; +import io.metersphere.log.vo.api.DefinitionReference; import io.metersphere.notice.sender.NoticeModel; import io.metersphere.notice.service.NoticeSendService; import io.metersphere.service.BaseProjectApplicationService; @@ -36,6 +38,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; +import org.jetbrains.annotations.NotNull; import org.json.JSONObject; import org.mybatis.spring.SqlSessionUtils; import org.springframework.stereotype.Service; @@ -76,6 +79,8 @@ public class ApiDefinitionImportUtilService { private ApiTestCaseService apiTestCaseService; @Resource private BaseUserService baseUserService; + @Resource + private ScheduleMapper scheduleMapper; public void checkUrl(ApiTestImportRequest request, Project project) { @@ -198,7 +203,8 @@ public class ApiDefinitionImportUtilService { ApiDefinitionMapper batchMapper = sqlSession.getMapper(ApiDefinitionMapper.class); ExtApiDefinitionMapper extApiDefinitionMapper = sqlSession.getMapper(ExtApiDefinitionMapper.class); ApiModuleMapper apiModuleMapper = sqlSession.getMapper(ApiModuleMapper.class); - + OperatingLogMapper operatingLogMapper = sqlSession.getMapper(OperatingLogMapper.class); + OperatingLogResourceMapper operatingLogResourceMapper = sqlSession.getMapper(OperatingLogResourceMapper.class); //系统内需要做更新操作的数据 List toUpdateList = new ArrayList<>(); //与当前导入接口重复的系统内所有数据 @@ -275,6 +281,10 @@ public class ApiDefinitionImportUtilService { ApiDefinitionImportParamDTO apiDefinitionImportParam = new ApiDefinitionImportParamDTO(item, request, apiImport.getMocks(), toUpdateList, caseList); apiDefinitionImportParam.setRepeatList(sameRefIds); + apiDefinitionImportParam.setImportType(request.getType()); + apiDefinitionImportParam.setScheduleId(request.getResourceId()); + apiDefinitionImportParam.setOperatingLogMapper(operatingLogMapper); + apiDefinitionImportParam.setOperatingLogResourceMapper(operatingLogResourceMapper); ApiImportSendNoticeDTO apiImportSendNoticeDTO = importCreate(batchMapper, apiDefinitionImportParam); if (apiImportSendNoticeDTO != null) { apiImportSendNoticeDTOS.add(apiImportSendNoticeDTO); @@ -1267,6 +1277,8 @@ public class ApiDefinitionImportUtilService { apiDefinition.setOrder(existApi.getOrder()); reSetImportMocksApiId(mocks, originId, apiDefinition.getId(), apiDefinition.getNum()); batchMapper.updateByPrimaryKeyWithBLOBs(apiDefinition); + //记录导入使得数据产生变更的操作记录 + setOperatingLog(existApi, apiDefinition, apiDefinitionImportParamDTO); ApiDefinitionResult apiDefinitionResult = ApiDefinitionImportUtil.getApiDefinitionResult(apiDefinition, true); apiImportSendNoticeDTO.setApiDefinitionResult(apiDefinitionResult); List apiTestCaseDTOS = importCase(apiDefinition, caseList); @@ -1279,6 +1291,58 @@ public class ApiDefinitionImportUtilService { return apiImportSendNoticeDTO; } + private void setOperatingLog(ApiDefinitionWithBLOBs existApi, ApiDefinitionWithBLOBs apiDefinition, ApiDefinitionImportParamDTO apiDefinitionImportParamDTO) { + OperatingLogWithBLOBs msOperLog = new OperatingLogWithBLOBs(); + msOperLog.setId(UUID.randomUUID().toString()); + msOperLog.setProjectId(existApi.getProjectId()); + msOperLog.setOperTitle(existApi.getName()); + msOperLog.setOperType(OperLogConstants.UPDATE.toString()); + setOperAndCreateUser(apiDefinitionImportParamDTO, msOperLog); + msOperLog.setOperModule(OperLogModule.API_DEFINITION); + msOperLog.setOperMethod("io.metersphere.api.controller.ApiDefinitionController.testCaseImport"); + msOperLog.setOperPath("/api/definition/import"); + OperatingLogDetails newDetails = getOperatingLogDetails(existApi, apiDefinition); + msOperLog.setOperContent(JSON.toJSONString(newDetails)); + msOperLog.setCreateUser(newDetails.getCreateUser()); + msOperLog.setOperTime(System.currentTimeMillis()); + OperatingLogResource operatingLogResource = new OperatingLogResource(); + operatingLogResource.setOperatingLogId(msOperLog.getId()); + operatingLogResource.setId(UUID.randomUUID().toString()); + operatingLogResource.setSourceId(existApi.getId()); + apiDefinitionImportParamDTO.getOperatingLogResourceMapper().insert(operatingLogResource); + apiDefinitionImportParamDTO.getOperatingLogMapper().insert(msOperLog); + } + + private void setOperAndCreateUser(ApiDefinitionImportParamDTO apiDefinitionImportParamDTO, OperatingLogWithBLOBs msOperLog) { + if (StringUtils.equals(apiDefinitionImportParamDTO.getImportType(), SCHEDULE)) { + ScheduleExample schedule = new ScheduleExample(); + schedule.createCriteria().andResourceIdEqualTo(apiDefinitionImportParamDTO.getScheduleId()); + List list = scheduleMapper.selectByExample(schedule); + if (list.size() > 0) { + User user = baseUserService.getUserDTO(list.get(0).getUserId()); + msOperLog.setOperUser(user.getName() + Translator.get("timing_synchronization")); + msOperLog.setCreateUser(user.getId()); + } else { + msOperLog.setOperUser(Translator.get("timing_synchronization")); + } + } else { + SessionUser user = SessionUtils.getUser(); + msOperLog.setOperUser(user.getName() + Translator.get("import_file")); + msOperLog.setCreateUser(user.getId()); + } + } + + @NotNull + private static OperatingLogDetails getOperatingLogDetails(ApiDefinitionWithBLOBs existApi, ApiDefinitionWithBLOBs apiDefinition) { + List oldColumns = ReflexObjectUtil.getColumns(existApi, DefinitionReference.definitionColumns); + OperatingLogDetails oldDetails = new OperatingLogDetails(JSON.toJSONString(existApi.getId()), existApi.getProjectId(), existApi.getName(), existApi.getCreateUser(), oldColumns); + List newColumns = ReflexObjectUtil.getColumns(apiDefinition, DefinitionReference.definitionColumns); + OperatingLogDetails newDetails = new OperatingLogDetails(JSON.toJSONString(apiDefinition.getId()), apiDefinition.getProjectId(), apiDefinition.getName(), apiDefinition.getCreateUser(), newColumns); + List columns = ReflexObjectUtil.compared(oldDetails, newDetails, OperLogModule.API_DEFINITION); + newDetails.setColumns(columns); + return newDetails; + } + private static List setRequestAndAddNewCase(ApiDefinitionWithBLOBs apiDefinition, List caseList, boolean newCreate) { boolean createCase = false; diff --git a/framework/sdk-parent/sdk/src/main/java/io/metersphere/log/service/OperatingLogService.java b/framework/sdk-parent/sdk/src/main/java/io/metersphere/log/service/OperatingLogService.java index 4ffb365e27..8de2898c90 100644 --- a/framework/sdk-parent/sdk/src/main/java/io/metersphere/log/service/OperatingLogService.java +++ b/framework/sdk-parent/sdk/src/main/java/io/metersphere/log/service/OperatingLogService.java @@ -129,7 +129,9 @@ public class OperatingLogService { if (CollectionUtils.isEmpty(logWithBLOB.getDetails().getColumns())) { dtos.add(logWithBLOB); } - + if (StringUtils.isBlank(logWithBLOB.getUserName()) && StringUtils.isNotBlank(logWithBLOB.getOperUser())) { + logWithBLOB.setUserName(logWithBLOB.getOperUser()); + } } } if (CollectionUtils.isNotEmpty(dtos)) { diff --git a/framework/sdk-parent/sdk/src/main/java/io/metersphere/log/utils/diff/json/JsonDiff.java b/framework/sdk-parent/sdk/src/main/java/io/metersphere/log/utils/diff/json/JsonDiff.java index 4a3d5e7249..c0a9fe320a 100644 --- a/framework/sdk-parent/sdk/src/main/java/io/metersphere/log/utils/diff/json/JsonDiff.java +++ b/framework/sdk-parent/sdk/src/main/java/io/metersphere/log/utils/diff/json/JsonDiff.java @@ -340,7 +340,7 @@ public class JsonDiff { if (childKey.startsWith("-")) { instruction.key = childKey.substring(1); //如果是删除多列 diff数据的key都是-1 ,会把数据给覆盖,所以这里 ke+下标 做新的index - instruction.index = isIndexed(instruction.key) == 1 ? isIndexed(instruction.key) + i : isIndexed(instruction.key); + instruction.index = isIndexed(instruction.key) == 1 ? isIndexed(instruction.key) : isIndexed(instruction.key) + i; instruction.oper = Oper.DELETE; } else if (childKey.startsWith("+")) { instruction.key = childKey.substring(1); diff --git a/framework/sdk-parent/sdk/src/main/java/io/metersphere/log/utils/diff/json/Leaf.java b/framework/sdk-parent/sdk/src/main/java/io/metersphere/log/utils/diff/json/Leaf.java index 48a2e05785..fa9b4778a1 100644 --- a/framework/sdk-parent/sdk/src/main/java/io/metersphere/log/utils/diff/json/Leaf.java +++ b/framework/sdk-parent/sdk/src/main/java/io/metersphere/log/utils/diff/json/Leaf.java @@ -134,7 +134,7 @@ class Leaf implements Comparable { String key = child.parent.toString(); String reIndexedKey = key; if (child.parent instanceof ArrNode) { - ((ArrNode) child.parent).index = i - deletes; + //((ArrNode) child.parent).index = i - deletes; reIndexedKey = child.parent.toString(); } JzonObject insert = factory.createJsonObject(); diff --git a/framework/sdk-parent/sdk/src/main/resources/i18n/commons_en_US.properties b/framework/sdk-parent/sdk/src/main/resources/i18n/commons_en_US.properties index 5727481253..fb4a095bd2 100644 --- a/framework/sdk-parent/sdk/src/main/resources/i18n/commons_en_US.properties +++ b/framework/sdk-parent/sdk/src/main/resources/i18n/commons_en_US.properties @@ -88,6 +88,8 @@ illegal_xml_format=illegal XML format api_report_is_null="Report is null, can't update" api_test_environment_already_exists="Api test environment already exists" api_test=API Test +import_file=Import File +timing_synchronization=Timing Synchronization #test case test_case_node_level=level test_case_node_level_tip=The node tree maximum depth is diff --git a/framework/sdk-parent/sdk/src/main/resources/i18n/commons_zh_CN.properties b/framework/sdk-parent/sdk/src/main/resources/i18n/commons_zh_CN.properties index 4226e92a10..2ce9235749 100644 --- a/framework/sdk-parent/sdk/src/main/resources/i18n/commons_zh_CN.properties +++ b/framework/sdk-parent/sdk/src/main/resources/i18n/commons_zh_CN.properties @@ -88,6 +88,8 @@ illegal_xml_format=不合法的 XML 格式 api_report_is_null="测试报告是未生成,无法更新" api_test_environment_already_exists="已存在该名称的环境配置" api_test=接口测试 +import_file=文件导入 +timing_synchronization=定时同步 #test case test_case_node_level=层 test_case_node_level_tip=模块树最大深度为 diff --git a/framework/sdk-parent/sdk/src/main/resources/i18n/commons_zh_TW.properties b/framework/sdk-parent/sdk/src/main/resources/i18n/commons_zh_TW.properties index 540090f0b5..689aec126b 100644 --- a/framework/sdk-parent/sdk/src/main/resources/i18n/commons_zh_TW.properties +++ b/framework/sdk-parent/sdk/src/main/resources/i18n/commons_zh_TW.properties @@ -88,6 +88,8 @@ illegal_xml_format=不合法的 XML 格式 api_report_is_null="測試報告是未生成,無法更新" api_test_environment_already_exists="已存在該名稱的環境配置" api_test=接口測試 +import_file=文件導入 +timing_synchronization=定時同步 #test case test_case_node_level=層 test_case_node_level_tip=模塊樹最大深度為