feat(项目设置): 文件管理支持对接第三方仓库

--task=1009630 --user=宋天阳 文件管理支持对接第三方仓库
https://www.tapd.cn/55049933/s/1243850
This commit is contained in:
song-tianyang 2022-09-05 17:01:31 +08:00 committed by 刘瑞斌
parent 531f007e2f
commit 1d534e7efd
72 changed files with 2848 additions and 258 deletions

View File

@ -26,6 +26,7 @@
<java-websocket.version>1.5.3</java-websocket.version>
<xmlbeans.version>5.1.0</xmlbeans.version>
<poi.version>5.1.0</poi.version>
<jgit.version>6.2.0.202206071550-r</jgit.version>
</properties>
<dependencies>
@ -403,6 +404,12 @@
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>${jgit.version}</version>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,16 @@
package io.metersphere.api.dto;
import io.metersphere.base.domain.FileMetadata;
import lombok.Getter;
import lombok.Setter;
import org.apache.jorphan.collections.HashTree;
import java.util.List;
@Getter
@Setter
public class HashTreeInfoDTO {
private String jmx;
private HashTree hashTree;
private List<FileMetadata> repositoryFiles;
}

View File

@ -3,10 +3,12 @@ package io.metersphere.api.dto;
import io.metersphere.base.domain.FileMetadata;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author song.tianyang
@ -33,4 +35,14 @@ public class JmxInfoDTO {
this.name = StringUtils.replace(name, "/", "");
}
public void addFileMetadataLists(List<FileMetadata> list) {
if (CollectionUtils.isNotEmpty(list)) {
List<String> fileMetadataIds = fileMetadataList.stream().map(FileMetadata::getId).collect(Collectors.toList());
list.forEach(item -> {
if (!fileMetadataIds.contains(item.getId())) {
fileMetadataList.add(item);
}
});
}
}
}

View File

@ -17,6 +17,7 @@ import io.metersphere.api.dto.scenario.request.BodyFile;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.commons.constants.DelimiterConstants;
import io.metersphere.commons.constants.LoopConstants;
@ -29,6 +30,7 @@ import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.i18n.Translator;
import io.metersphere.jmeter.utils.ScriptEngineUtils;
import io.metersphere.metadata.service.FileMetadataService;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.service.EnvironmentGroupProjectService;
@ -106,6 +108,7 @@ public class ElementUtil {
list = config.getTransferVariables().stream().filter(ScenarioVariable::isCSVValid).filter(ScenarioVariable::isEnable).collect(Collectors.toList());
}
if (CollectionUtils.isNotEmpty(list)) {
FileMetadataService fileMetadataService = CommonBeanFactory.getBean(FileMetadataService.class);
list.forEach(item -> {
CSVDataSet csvDataSet = new CSVDataSet();
csvDataSet.setEnabled(true);
@ -116,15 +119,28 @@ public class ElementUtil {
if (CollectionUtils.isEmpty(item.getFiles())) {
MSException.throwException(StringUtils.isEmpty(item.getName()) ? "CSVDataSet" : item.getName() + "[ " + Translator.get("csv_no_exist") + " ]");
} else {
boolean isRef = false;
String fileId = null;
boolean isRepository = false;
BodyFile file = item.getFiles().get(0);
String path = BODY_FILE_DIR + "/" + item.getFiles().get(0).getId() + "_" + item.getFiles().get(0).getName();
if (StringUtils.equalsIgnoreCase(file.getStorage(), StorageConstants.FILE_REF.name())) {
isRef = true;
fileId = file.getFileId();
if (fileMetadataService != null) {
FileMetadata fileMetadata = fileMetadataService.getFileMetadataById(fileId);
if (fileMetadata != null && StringUtils.equals(fileMetadata.getStorage(), StorageConstants.GIT.name())) {
isRepository = true;
}
}
path = FileUtils.getFilePath(file);
}
if (!config.isOperating() && !new File(path).exists()) {
if (!config.isOperating() && !isRepository && !new File(path).exists()) {
MSException.throwException(StringUtils.isEmpty(item.getName()) ? "CSVDataSet" : item.getName() + "[ " + Translator.get("csv_no_exist") + " ]");
}
csvDataSet.setProperty("filename", path);
csvDataSet.setProperty("isRef", isRef);
csvDataSet.setProperty("fileId", fileId);
}
csvDataSet.setIgnoreFirstLine(false);
csvDataSet.setProperty("shareMode", shareMode);

View File

@ -148,9 +148,13 @@ public class Body {
KeyValue keyValue, String requestId, boolean isBinary) {
if (files != null) {
files.forEach(file -> {
boolean isRef = false;
String fileId = null;
String paramName = keyValue.getName() == null ? requestId : keyValue.getName();
String path = null;
if (StringUtils.equalsIgnoreCase(file.getStorage(), StorageConstants.FILE_REF.name())) {
isRef = true;
fileId = file.getFileId();
path = FileUtils.getFilePath(file);
} else if (StringUtils.isNotBlank(file.getId()) && !isBinary) {
// 旧数据
@ -164,7 +168,10 @@ public class Body {
if (StringUtils.isBlank(mimetype)) {
mimetype = ContentType.APPLICATION_OCTET_STREAM.getMimeType();
}
list.add(new HTTPFileArg(path, isBinary ? "" : paramName, mimetype));
HTTPFileArg fileArg = new HTTPFileArg(path, isBinary ? "" : paramName, mimetype);
fileArg.setProperty("isRef", isRef);
fileArg.setProperty("fileId", fileId);
list.add(fileArg);
});
}
}

View File

@ -8,7 +8,7 @@ import org.apache.commons.lang.StringUtils;
public class BodyFile {
private String id;
private String name;
// LOCAL 引用(FILE_REF)
// LOCAL 引用(FILE_REF) / GIT
private String storage;
private String fileId;
private String projectId;

View File

@ -28,7 +28,9 @@ import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.MsExecResponseDTO;

View File

@ -7,7 +7,10 @@ import io.metersphere.api.exec.utils.RequestParamsUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.jmeter.utils.SmoothWeighted;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.*;
import io.metersphere.base.domain.ApiExecutionQueueDetail;
import io.metersphere.base.domain.ApiScenarioReport;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.TestPlanApiScenario;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiScenarioReportMapper;
import io.metersphere.base.mapper.TestPlanApiScenarioMapper;

View File

@ -8,6 +8,7 @@ import io.metersphere.api.jmeter.utils.SmoothWeighted;
import io.metersphere.api.service.RemakeReportService;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.HashTreeUtil;
import io.metersphere.config.JmeterProperties;
import io.metersphere.config.KafkaConfig;
import io.metersphere.constants.BackendListenerConstants;
@ -189,6 +190,8 @@ public class JMeterService {
if (request.getPool().isPool() && StringUtils.isNotBlank(request.getRunMode()) && !request.getRunMode().startsWith("UI")) {
this.runNode(request);
} else {
//解析hashTree是否含有文件库文件
HashTreeUtil.initRepositoryFiles(request);
CommonBeanFactory.getBean(ExecThreadPoolExecutor.class).addTask(request);
}
}

View File

@ -7,6 +7,7 @@ import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.service.TestResultService;
import io.metersphere.cache.JMeterEngineCache;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.constants.BackendListenerConstants;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.ResultDTO;
@ -82,6 +83,7 @@ public class MsApiBackendListener extends AbstractBackendListenerClient implemen
} catch (Exception e) {
LoggerUtil.error("结果集处理异常", dto.getReportId(), e);
} finally {
FileUtils.deleteBodyFiles(dto.getReportId());
if (FileServer.getFileServer() != null) {
LoggerUtil.info("进入监听开始关闭CSV", dto.getReportId());
FileServer.getFileServer().closeCsv(dto.getReportId());

View File

@ -23,7 +23,9 @@ import io.metersphere.api.dto.RequestResultExpandDTO;
import io.metersphere.api.dto.RunningParamKeys;
import io.metersphere.api.exec.queue.PoolExecBlockingQueueUtil;
import io.metersphere.api.exec.utils.ResultParseUtil;
import io.metersphere.commons.utils.*;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ResponseUtil;
import io.metersphere.dto.RequestResult;
import io.metersphere.jmeter.JMeterBase;
import io.metersphere.utils.JMeterVars;
@ -108,6 +110,7 @@ public class MsDebugListener extends AbstractListenerElement implements SampleLi
WebSocketUtils.sendMessageSingle(dto);
WebSocketUtils.onClose(this.getName());
PoolExecBlockingQueueUtil.offer(this.getName());
FileUtils.deleteBodyFiles(this.getName());
}
@Override

View File

@ -890,8 +890,10 @@ public class ApiAutomationService {
}
private String generateJmx(ApiScenarioWithBLOBs apiScenario) {
private HashTreeInfoDTO generateJmx(ApiScenarioWithBLOBs apiScenario) {
String jmx = null;
HashTree jmeterHashTree = new ListedHashTree();
List<FileMetadata> repositoryMetadata = new ArrayList<>();
MsTestPlan testPlan = new MsTestPlan();
// 获取自定义JAR
String projectId = apiScenario.getProjectId();
@ -931,7 +933,8 @@ public class ApiAutomationService {
if (isUseElement) {
scenario.toHashTree(jmeterHashTree, scenario.getHashTree(), config);
ElementUtil.accuracyHashTree(jmeterHashTree);
return scenario.getJmx(jmeterHashTree);
repositoryMetadata = FileUtils.getRepositoryFileMetadata(jmeterHashTree);
jmx = scenario.getJmx(jmeterHashTree);
} else {
MsThreadGroup group = new MsThreadGroup();
group.setLabel(apiScenario.getName());
@ -942,13 +945,22 @@ public class ApiAutomationService {
this.add(scenario);
}});
testPlan.getHashTree().add(group);
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), config);
repositoryMetadata = FileUtils.getRepositoryFileMetadata(jmeterHashTree);
jmx = testPlan.getJmx(jmeterHashTree);
}
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), config);
} catch (Exception ex) {
LogUtil.error(ex);
MSException.throwException(ex.getMessage());
}
return testPlan.getJmx(jmeterHashTree);
HashTreeInfoDTO returnDTO = new HashTreeInfoDTO();
returnDTO.setJmx(jmx);
returnDTO.setHashTree(jmeterHashTree);
returnDTO.setRepositoryFiles(repositoryMetadata);
return returnDTO;
}
@ -1143,7 +1155,11 @@ public class ApiAutomationService {
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
ApiScenarioDTO scenario = apiScenarios.get(0);
JmxInfoDTO jmxInfo = apiTestService.updateJmxString(generateJmx(scenario), scenario.getProjectId(), true);
HashTreeInfoDTO hashTreeInfoDTO = generateJmx(scenario);
JmxInfoDTO jmxInfo = apiTestService.updateJmxString(hashTreeInfoDTO.getJmx(), scenario.getProjectId(), true);
jmxInfo.addFileMetadataLists(hashTreeInfoDTO.getRepositoryFiles());
String name = request.getName() + ".jmx";
jmxInfo.setName(name);
jmxInfo.setId(id);
@ -1677,10 +1693,11 @@ public class ApiAutomationService {
apiScenarioWithBLOBs.forEach(item -> {
if (StringUtils.isNotEmpty(item.getScenarioDefinition())) {
String jmx = generateJmx(item);
if (StringUtils.isNotEmpty(jmx)) {
ApiScenarioExportJmxDTO scenariosExportJmx = new ApiScenarioExportJmxDTO(item.getName(), apiTestService.updateJmxString(jmx, item.getProjectId(), false).getXml());
JmxInfoDTO dto = apiTestService.updateJmxString(jmx, item.getProjectId(), true);
HashTreeInfoDTO hashTreeInfoDTO = generateJmx(item);
if (StringUtils.isNotEmpty(hashTreeInfoDTO.getJmx())) {
ApiScenarioExportJmxDTO scenariosExportJmx = new ApiScenarioExportJmxDTO(item.getName(), apiTestService.updateJmxString(hashTreeInfoDTO.getJmx(), item.getProjectId(), false).getXml());
JmxInfoDTO dto = apiTestService.updateJmxString(hashTreeInfoDTO.getJmx(), item.getProjectId(), true);
dto.addFileMetadataLists(hashTreeInfoDTO.getRepositoryFiles());
scenariosExportJmx.setId(item.getId());
scenariosExportJmx.setVersion(item.getVersion());
//扫描需要哪些文件
@ -1713,9 +1730,9 @@ public class ApiAutomationService {
Map<String, byte[]> files = new LinkedHashMap<>();
scenarios.forEach(item -> {
if (StringUtils.isNotEmpty(item.getScenarioDefinition())) {
String jmx = generateJmx(item);
if (StringUtils.isNotEmpty(jmx)) {
ApiScenarioExportJmxDTO scenariosExportJmx = new ApiScenarioExportJmxDTO(item.getName(), apiTestService.updateJmxString(jmx, item.getProjectId(), false).getXml());
HashTreeInfoDTO hashTreeInfoDTO = generateJmx(item);
if (StringUtils.isNotEmpty(hashTreeInfoDTO.getJmx())) {
ApiScenarioExportJmxDTO scenariosExportJmx = new ApiScenarioExportJmxDTO(item.getName(), apiTestService.updateJmxString(hashTreeInfoDTO.getJmx(), item.getProjectId(), false).getXml());
String fileName = item.getName() + ".jmx";
String jmxStr = scenariosExportJmx.getJmx();
files.put(fileName, jmxStr.getBytes(StandardCharsets.UTF_8));
@ -2032,7 +2049,9 @@ public class ApiAutomationService {
apiScenarioList.forEach(item -> {
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
JmxInfoDTO dto = apiTestService.updateJmxString(generateJmx(item), item.getProjectId(), true);
HashTreeInfoDTO hashTreeInfoDTO = generateJmx(item);
JmxInfoDTO dto = apiTestService.updateJmxString(hashTreeInfoDTO.getJmx(), item.getProjectId(), true);
dto.setFileMetadataList(hashTreeInfoDTO.getRepositoryFiles());
String name = item.getName() + ".jmx";
dto.setId(item.getId());
dto.setName(name);

View File

@ -11,11 +11,13 @@ import io.metersphere.base.mapper.ApiExecutionQueueDetailMapper;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.TestPlanApiScenarioMapper;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.StorageConstants;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.metadata.service.FileMetadataService;
import io.metersphere.metadata.vo.repository.FileInfoDTO;
import io.metersphere.service.EnvironmentGroupProjectService;
import io.metersphere.service.PluginService;
import io.metersphere.utils.LoggerUtil;
@ -46,6 +48,8 @@ public class ApiJMeterFileService {
private ApiExecutionQueueDetailMapper executionQueueDetailMapper;
@Resource
private EnvironmentGroupProjectService environmentGroupProjectService;
@Resource
private FileMetadataService fileMetadataService;
// 接口测试 用例/接口
private static final List<String> CASE_MODES = new ArrayList<>() {{
this.add(ApiRunMode.DEFINITION.name());
@ -211,21 +215,34 @@ public class ApiJMeterFileService {
return jarFiles;
}
private Map<String, byte[]> getMultipartFiles(HashTree hashTree) {
private Map<String, byte[]> getMultipartFiles(String reportId, HashTree hashTree) {
Map<String, byte[]> multipartFiles = new LinkedHashMap<>();
// 获取附件
List<BodyFile> files = new LinkedList<>();
FileUtils.getFiles(hashTree, files);
FileUtils.getExecuteFiles(hashTree, reportId, files);
if (CollectionUtils.isNotEmpty(files)) {
Map<String, String> repositoryFileMap = new HashMap<>();
for (BodyFile bodyFile : files) {
File file = new File(bodyFile.getName());
if (file != null && file.exists()) {
byte[] fileByte = FileUtils.fileToByte(file);
if (fileByte != null) {
multipartFiles.put(file.getAbsolutePath(), fileByte);
if (StringUtils.equals(bodyFile.getStorage(), StorageConstants.GIT.name())
&& StringUtils.isNotBlank(bodyFile.getFileId())) {
repositoryFileMap.put(bodyFile.getFileId(), bodyFile.getName());
} else {
File file = new File(bodyFile.getName());
if (file != null && file.exists()) {
byte[] fileByte = FileUtils.fileToByte(file);
if (fileByte != null) {
multipartFiles.put(file.getAbsolutePath(), fileByte);
}
}
}
}
List<FileInfoDTO> fileInfoDTOList = fileMetadataService.downloadFileByIds(repositoryFileMap.keySet());
fileInfoDTOList.forEach(repositoryFile -> {
if (repositoryFile.getFileByte() != null) {
multipartFiles.put(FileUtils.BODY_FILE_DIR + File.separator + repositoryFileMap.get(repositoryFile.getId()), repositoryFile.getFileByte());
}
});
}
return multipartFiles;
}
@ -242,6 +259,10 @@ public class ApiJMeterFileService {
private byte[] zipFilesToByteArray(String testId, HashTree hashTree) {
String bodyFilePath = FileUtils.BODY_FILE_DIR;
String fileName = testId + ".jmx";
// 获取JMX使用到的附件
Map<String, byte[]> multipartFiles = this.getMultipartFiles(testId, hashTree);
String jmx = new MsTestPlan().getJmx(hashTree);
// 处理dubbo请求生成jmx文件
if (StringUtils.isNotEmpty(jmx)) {
@ -250,8 +271,7 @@ public class ApiJMeterFileService {
Map<String, byte[]> files = new HashMap<>();
// 每个测试生成一个文件夹
files.put(fileName, jmx.getBytes(StandardCharsets.UTF_8));
// 获取JMX使用到的附件
Map<String, byte[]> multipartFiles = this.getMultipartFiles(hashTree);
if (multipartFiles != null && !multipartFiles.isEmpty()) {
for (String k : multipartFiles.keySet()) {
byte[] v = multipartFiles.get(k);

View File

@ -35,7 +35,9 @@ public class FileMetadata implements Serializable {
private String resourceType;
private String description;
private Boolean latest;
private String refId;
private static final long serialVersionUID = 1L;
}

View File

@ -1113,6 +1113,136 @@ public class FileMetadataExample {
addCriterion("resource_type not between", value1, value2, "resourceType");
return (Criteria) this;
}
public Criteria andLatestIsNull() {
addCriterion("latest is null");
return (Criteria) this;
}
public Criteria andLatestIsNotNull() {
addCriterion("latest is not null");
return (Criteria) this;
}
public Criteria andLatestEqualTo(Boolean value) {
addCriterion("latest =", value, "latest");
return (Criteria) this;
}
public Criteria andLatestNotEqualTo(Boolean value) {
addCriterion("latest <>", value, "latest");
return (Criteria) this;
}
public Criteria andLatestGreaterThan(Boolean value) {
addCriterion("latest >", value, "latest");
return (Criteria) this;
}
public Criteria andLatestGreaterThanOrEqualTo(Boolean value) {
addCriterion("latest >=", value, "latest");
return (Criteria) this;
}
public Criteria andLatestLessThan(Boolean value) {
addCriterion("latest <", value, "latest");
return (Criteria) this;
}
public Criteria andLatestLessThanOrEqualTo(Boolean value) {
addCriterion("latest <=", value, "latest");
return (Criteria) this;
}
public Criteria andLatestIn(List<Boolean> values) {
addCriterion("latest in", values, "latest");
return (Criteria) this;
}
public Criteria andLatestNotIn(List<Boolean> values) {
addCriterion("latest not in", values, "latest");
return (Criteria) this;
}
public Criteria andLatestBetween(Boolean value1, Boolean value2) {
addCriterion("latest between", value1, value2, "latest");
return (Criteria) this;
}
public Criteria andLatestNotBetween(Boolean value1, Boolean value2) {
addCriterion("latest not between", value1, value2, "latest");
return (Criteria) this;
}
public Criteria andRefIdIsNull() {
addCriterion("ref_id is null");
return (Criteria) this;
}
public Criteria andRefIdIsNotNull() {
addCriterion("ref_id is not null");
return (Criteria) this;
}
public Criteria andRefIdEqualTo(String value) {
addCriterion("ref_id =", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotEqualTo(String value) {
addCriterion("ref_id <>", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdGreaterThan(String value) {
addCriterion("ref_id >", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdGreaterThanOrEqualTo(String value) {
addCriterion("ref_id >=", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdLessThan(String value) {
addCriterion("ref_id <", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdLessThanOrEqualTo(String value) {
addCriterion("ref_id <=", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdLike(String value) {
addCriterion("ref_id like", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotLike(String value) {
addCriterion("ref_id not like", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdIn(List<String> values) {
addCriterion("ref_id in", values, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotIn(List<String> values) {
addCriterion("ref_id not in", values, "refId");
return (Criteria) this;
}
public Criteria andRefIdBetween(String value1, String value2) {
addCriterion("ref_id between", value1, value2, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotBetween(String value1, String value2) {
addCriterion("ref_id not between", value1, value2, "refId");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -0,0 +1,17 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class FileMetadataWithBLOBs extends FileMetadata implements Serializable {
private String description;
private String attachInfo;
private static final long serialVersionUID = 1L;
}

View File

@ -23,5 +23,15 @@ public class FileModule implements Serializable {
private String createUser;
private String moduleType;
private String repositoryPath;
private String repositoryToken;
private String repositoryUserName;
private String repositoryDesc;
private static final long serialVersionUID = 1L;
}

View File

@ -693,6 +693,286 @@ public class FileModuleExample {
addCriterion("create_user not between", value1, value2, "createUser");
return (Criteria) this;
}
public Criteria andModuleTypeIsNull() {
addCriterion("module_type is null");
return (Criteria) this;
}
public Criteria andModuleTypeIsNotNull() {
addCriterion("module_type is not null");
return (Criteria) this;
}
public Criteria andModuleTypeEqualTo(String value) {
addCriterion("module_type =", value, "moduleType");
return (Criteria) this;
}
public Criteria andModuleTypeNotEqualTo(String value) {
addCriterion("module_type <>", value, "moduleType");
return (Criteria) this;
}
public Criteria andModuleTypeGreaterThan(String value) {
addCriterion("module_type >", value, "moduleType");
return (Criteria) this;
}
public Criteria andModuleTypeGreaterThanOrEqualTo(String value) {
addCriterion("module_type >=", value, "moduleType");
return (Criteria) this;
}
public Criteria andModuleTypeLessThan(String value) {
addCriterion("module_type <", value, "moduleType");
return (Criteria) this;
}
public Criteria andModuleTypeLessThanOrEqualTo(String value) {
addCriterion("module_type <=", value, "moduleType");
return (Criteria) this;
}
public Criteria andModuleTypeLike(String value) {
addCriterion("module_type like", value, "moduleType");
return (Criteria) this;
}
public Criteria andModuleTypeNotLike(String value) {
addCriterion("module_type not like", value, "moduleType");
return (Criteria) this;
}
public Criteria andModuleTypeIn(List<String> values) {
addCriterion("module_type in", values, "moduleType");
return (Criteria) this;
}
public Criteria andModuleTypeNotIn(List<String> values) {
addCriterion("module_type not in", values, "moduleType");
return (Criteria) this;
}
public Criteria andModuleTypeBetween(String value1, String value2) {
addCriterion("module_type between", value1, value2, "moduleType");
return (Criteria) this;
}
public Criteria andModuleTypeNotBetween(String value1, String value2) {
addCriterion("module_type not between", value1, value2, "moduleType");
return (Criteria) this;
}
public Criteria andRepositoryPathIsNull() {
addCriterion("repository_path is null");
return (Criteria) this;
}
public Criteria andRepositoryPathIsNotNull() {
addCriterion("repository_path is not null");
return (Criteria) this;
}
public Criteria andRepositoryPathEqualTo(String value) {
addCriterion("repository_path =", value, "repositoryPath");
return (Criteria) this;
}
public Criteria andRepositoryPathNotEqualTo(String value) {
addCriterion("repository_path <>", value, "repositoryPath");
return (Criteria) this;
}
public Criteria andRepositoryPathGreaterThan(String value) {
addCriterion("repository_path >", value, "repositoryPath");
return (Criteria) this;
}
public Criteria andRepositoryPathGreaterThanOrEqualTo(String value) {
addCriterion("repository_path >=", value, "repositoryPath");
return (Criteria) this;
}
public Criteria andRepositoryPathLessThan(String value) {
addCriterion("repository_path <", value, "repositoryPath");
return (Criteria) this;
}
public Criteria andRepositoryPathLessThanOrEqualTo(String value) {
addCriterion("repository_path <=", value, "repositoryPath");
return (Criteria) this;
}
public Criteria andRepositoryPathLike(String value) {
addCriterion("repository_path like", value, "repositoryPath");
return (Criteria) this;
}
public Criteria andRepositoryPathNotLike(String value) {
addCriterion("repository_path not like", value, "repositoryPath");
return (Criteria) this;
}
public Criteria andRepositoryPathIn(List<String> values) {
addCriterion("repository_path in", values, "repositoryPath");
return (Criteria) this;
}
public Criteria andRepositoryPathNotIn(List<String> values) {
addCriterion("repository_path not in", values, "repositoryPath");
return (Criteria) this;
}
public Criteria andRepositoryPathBetween(String value1, String value2) {
addCriterion("repository_path between", value1, value2, "repositoryPath");
return (Criteria) this;
}
public Criteria andRepositoryPathNotBetween(String value1, String value2) {
addCriterion("repository_path not between", value1, value2, "repositoryPath");
return (Criteria) this;
}
public Criteria andRepositoryTokenIsNull() {
addCriterion("repository_token is null");
return (Criteria) this;
}
public Criteria andRepositoryTokenIsNotNull() {
addCriterion("repository_token is not null");
return (Criteria) this;
}
public Criteria andRepositoryTokenEqualTo(String value) {
addCriterion("repository_token =", value, "repositoryToken");
return (Criteria) this;
}
public Criteria andRepositoryTokenNotEqualTo(String value) {
addCriterion("repository_token <>", value, "repositoryToken");
return (Criteria) this;
}
public Criteria andRepositoryTokenGreaterThan(String value) {
addCriterion("repository_token >", value, "repositoryToken");
return (Criteria) this;
}
public Criteria andRepositoryTokenGreaterThanOrEqualTo(String value) {
addCriterion("repository_token >=", value, "repositoryToken");
return (Criteria) this;
}
public Criteria andRepositoryTokenLessThan(String value) {
addCriterion("repository_token <", value, "repositoryToken");
return (Criteria) this;
}
public Criteria andRepositoryTokenLessThanOrEqualTo(String value) {
addCriterion("repository_token <=", value, "repositoryToken");
return (Criteria) this;
}
public Criteria andRepositoryTokenLike(String value) {
addCriterion("repository_token like", value, "repositoryToken");
return (Criteria) this;
}
public Criteria andRepositoryTokenNotLike(String value) {
addCriterion("repository_token not like", value, "repositoryToken");
return (Criteria) this;
}
public Criteria andRepositoryTokenIn(List<String> values) {
addCriterion("repository_token in", values, "repositoryToken");
return (Criteria) this;
}
public Criteria andRepositoryTokenNotIn(List<String> values) {
addCriterion("repository_token not in", values, "repositoryToken");
return (Criteria) this;
}
public Criteria andRepositoryTokenBetween(String value1, String value2) {
addCriterion("repository_token between", value1, value2, "repositoryToken");
return (Criteria) this;
}
public Criteria andRepositoryTokenNotBetween(String value1, String value2) {
addCriterion("repository_token not between", value1, value2, "repositoryToken");
return (Criteria) this;
}
public Criteria andRepositoryUserNameIsNull() {
addCriterion("repository_user_name is null");
return (Criteria) this;
}
public Criteria andRepositoryUserNameIsNotNull() {
addCriterion("repository_user_name is not null");
return (Criteria) this;
}
public Criteria andRepositoryUserNameEqualTo(String value) {
addCriterion("repository_user_name =", value, "repositoryUserName");
return (Criteria) this;
}
public Criteria andRepositoryUserNameNotEqualTo(String value) {
addCriterion("repository_user_name <>", value, "repositoryUserName");
return (Criteria) this;
}
public Criteria andRepositoryUserNameGreaterThan(String value) {
addCriterion("repository_user_name >", value, "repositoryUserName");
return (Criteria) this;
}
public Criteria andRepositoryUserNameGreaterThanOrEqualTo(String value) {
addCriterion("repository_user_name >=", value, "repositoryUserName");
return (Criteria) this;
}
public Criteria andRepositoryUserNameLessThan(String value) {
addCriterion("repository_user_name <", value, "repositoryUserName");
return (Criteria) this;
}
public Criteria andRepositoryUserNameLessThanOrEqualTo(String value) {
addCriterion("repository_user_name <=", value, "repositoryUserName");
return (Criteria) this;
}
public Criteria andRepositoryUserNameLike(String value) {
addCriterion("repository_user_name like", value, "repositoryUserName");
return (Criteria) this;
}
public Criteria andRepositoryUserNameNotLike(String value) {
addCriterion("repository_user_name not like", value, "repositoryUserName");
return (Criteria) this;
}
public Criteria andRepositoryUserNameIn(List<String> values) {
addCriterion("repository_user_name in", values, "repositoryUserName");
return (Criteria) this;
}
public Criteria andRepositoryUserNameNotIn(List<String> values) {
addCriterion("repository_user_name not in", values, "repositoryUserName");
return (Criteria) this;
}
public Criteria andRepositoryUserNameBetween(String value1, String value2) {
addCriterion("repository_user_name between", value1, value2, "repositoryUserName");
return (Criteria) this;
}
public Criteria andRepositoryUserNameNotBetween(String value1, String value2) {
addCriterion("repository_user_name not between", value1, value2, "repositoryUserName");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -2,6 +2,7 @@ package io.metersphere.base.mapper;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.FileMetadataExample;
import io.metersphere.base.domain.FileMetadataWithBLOBs;
import java.util.List;
import org.apache.ibatis.annotations.Param;
@ -12,25 +13,25 @@ public interface FileMetadataMapper {
int deleteByPrimaryKey(String id);
int insert(FileMetadata record);
int insert(FileMetadataWithBLOBs record);
int insertSelective(FileMetadata record);
int insertSelective(FileMetadataWithBLOBs record);
List<FileMetadata> selectByExampleWithBLOBs(FileMetadataExample example);
List<FileMetadataWithBLOBs> selectByExampleWithBLOBs(FileMetadataExample example);
List<FileMetadata> selectByExample(FileMetadataExample example);
FileMetadata selectByPrimaryKey(String id);
FileMetadataWithBLOBs selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") FileMetadata record, @Param("example") FileMetadataExample example);
int updateByExampleSelective(@Param("record") FileMetadataWithBLOBs record, @Param("example") FileMetadataExample example);
int updateByExampleWithBLOBs(@Param("record") FileMetadata record, @Param("example") FileMetadataExample example);
int updateByExampleWithBLOBs(@Param("record") FileMetadataWithBLOBs record, @Param("example") FileMetadataExample example);
int updateByExample(@Param("record") FileMetadata record, @Param("example") FileMetadataExample example);
int updateByPrimaryKeySelective(FileMetadata record);
int updateByPrimaryKeySelective(FileMetadataWithBLOBs record);
int updateByPrimaryKeyWithBLOBs(FileMetadata record);
int updateByPrimaryKeyWithBLOBs(FileMetadataWithBLOBs record);
int updateByPrimaryKey(FileMetadata record);
}

View File

@ -17,9 +17,12 @@
<result column="load_jar" jdbcType="BIT" property="loadJar" />
<result column="path" jdbcType="VARCHAR" property="path" />
<result column="resource_type" jdbcType="VARCHAR" property="resourceType" />
<result column="latest" jdbcType="BIT" property="latest" />
<result column="ref_id" jdbcType="VARCHAR" property="refId" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.FileMetadata">
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.FileMetadataWithBLOBs">
<result column="description" jdbcType="LONGVARCHAR" property="description" />
<result column="attach_info" jdbcType="LONGVARCHAR" property="attachInfo" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -81,10 +84,10 @@
</sql>
<sql id="Base_Column_List">
id, `name`, `type`, `size`, create_time, update_time, project_id, `storage`, create_user,
update_user, tags, module_id, load_jar, `path`, resource_type
update_user, tags, module_id, load_jar, `path`, resource_type, latest, ref_id
</sql>
<sql id="Blob_Column_List">
description
description, attach_info
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.FileMetadataExample" resultMap="ResultMapWithBLOBs">
select
@ -134,21 +137,23 @@
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.FileMetadata">
<insert id="insert" parameterType="io.metersphere.base.domain.FileMetadataWithBLOBs">
insert into file_metadata (id, `name`, `type`,
`size`, create_time, update_time,
project_id, `storage`, create_user,
update_user, tags, module_id,
load_jar, `path`, resource_type,
description)
latest, ref_id, description,
attach_info)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR},
#{size,jdbcType=BIGINT}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{projectId,jdbcType=VARCHAR}, #{storage,jdbcType=VARCHAR}, #{createUser,jdbcType=VARCHAR},
#{updateUser,jdbcType=VARCHAR}, #{tags,jdbcType=VARCHAR}, #{moduleId,jdbcType=VARCHAR},
#{loadJar,jdbcType=BIT}, #{path,jdbcType=VARCHAR}, #{resourceType,jdbcType=VARCHAR},
#{description,jdbcType=LONGVARCHAR})
#{latest,jdbcType=BIT}, #{refId,jdbcType=VARCHAR}, #{description,jdbcType=LONGVARCHAR},
#{attachInfo,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.FileMetadata">
<insert id="insertSelective" parameterType="io.metersphere.base.domain.FileMetadataWithBLOBs">
insert into file_metadata
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -196,9 +201,18 @@
<if test="resourceType != null">
resource_type,
</if>
<if test="latest != null">
latest,
</if>
<if test="refId != null">
ref_id,
</if>
<if test="description != null">
description,
</if>
<if test="attachInfo != null">
attach_info,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -246,9 +260,18 @@
<if test="resourceType != null">
#{resourceType,jdbcType=VARCHAR},
</if>
<if test="latest != null">
#{latest,jdbcType=BIT},
</if>
<if test="refId != null">
#{refId,jdbcType=VARCHAR},
</if>
<if test="description != null">
#{description,jdbcType=LONGVARCHAR},
</if>
<if test="attachInfo != null">
#{attachInfo,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.FileMetadataExample" resultType="java.lang.Long">
@ -305,9 +328,18 @@
<if test="record.resourceType != null">
resource_type = #{record.resourceType,jdbcType=VARCHAR},
</if>
<if test="record.latest != null">
latest = #{record.latest,jdbcType=BIT},
</if>
<if test="record.refId != null">
ref_id = #{record.refId,jdbcType=VARCHAR},
</if>
<if test="record.description != null">
description = #{record.description,jdbcType=LONGVARCHAR},
</if>
<if test="record.attachInfo != null">
attach_info = #{record.attachInfo,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -330,7 +362,10 @@
load_jar = #{record.loadJar,jdbcType=BIT},
`path` = #{record.path,jdbcType=VARCHAR},
resource_type = #{record.resourceType,jdbcType=VARCHAR},
description = #{record.description,jdbcType=LONGVARCHAR}
latest = #{record.latest,jdbcType=BIT},
ref_id = #{record.refId,jdbcType=VARCHAR},
description = #{record.description,jdbcType=LONGVARCHAR},
attach_info = #{record.attachInfo,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -351,12 +386,14 @@
module_id = #{record.moduleId,jdbcType=VARCHAR},
load_jar = #{record.loadJar,jdbcType=BIT},
`path` = #{record.path,jdbcType=VARCHAR},
resource_type = #{record.resourceType,jdbcType=VARCHAR}
resource_type = #{record.resourceType,jdbcType=VARCHAR},
latest = #{record.latest,jdbcType=BIT},
ref_id = #{record.refId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.FileMetadata">
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.FileMetadataWithBLOBs">
update file_metadata
<set>
<if test="name != null">
@ -401,13 +438,22 @@
<if test="resourceType != null">
resource_type = #{resourceType,jdbcType=VARCHAR},
</if>
<if test="latest != null">
latest = #{latest,jdbcType=BIT},
</if>
<if test="refId != null">
ref_id = #{refId,jdbcType=VARCHAR},
</if>
<if test="description != null">
description = #{description,jdbcType=LONGVARCHAR},
</if>
<if test="attachInfo != null">
attach_info = #{attachInfo,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.FileMetadata">
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.FileMetadataWithBLOBs">
update file_metadata
set `name` = #{name,jdbcType=VARCHAR},
`type` = #{type,jdbcType=VARCHAR},
@ -423,7 +469,10 @@
load_jar = #{loadJar,jdbcType=BIT},
`path` = #{path,jdbcType=VARCHAR},
resource_type = #{resourceType,jdbcType=VARCHAR},
description = #{description,jdbcType=LONGVARCHAR}
latest = #{latest,jdbcType=BIT},
ref_id = #{refId,jdbcType=VARCHAR},
description = #{description,jdbcType=LONGVARCHAR},
attach_info = #{attachInfo,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.FileMetadata">
@ -441,7 +490,9 @@
module_id = #{moduleId,jdbcType=VARCHAR},
load_jar = #{loadJar,jdbcType=BIT},
`path` = #{path,jdbcType=VARCHAR},
resource_type = #{resourceType,jdbcType=VARCHAR}
resource_type = #{resourceType,jdbcType=VARCHAR},
latest = #{latest,jdbcType=BIT},
ref_id = #{refId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -16,15 +16,21 @@ public interface FileModuleMapper {
int insertSelective(FileModule record);
List<FileModule> selectByExampleWithBLOBs(FileModuleExample example);
List<FileModule> selectByExample(FileModuleExample example);
FileModule selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") FileModule record, @Param("example") FileModuleExample example);
int updateByExampleWithBLOBs(@Param("record") FileModule record, @Param("example") FileModuleExample example);
int updateByExample(@Param("record") FileModule record, @Param("example") FileModuleExample example);
int updateByPrimaryKeySelective(FileModule record);
int updateByPrimaryKeyWithBLOBs(FileModule record);
int updateByPrimaryKey(FileModule record);
}

View File

@ -11,6 +11,13 @@
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="pos" jdbcType="DOUBLE" property="pos" />
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
<result column="module_type" jdbcType="VARCHAR" property="moduleType" />
<result column="repository_path" jdbcType="VARCHAR" property="repositoryPath" />
<result column="repository_token" jdbcType="VARCHAR" property="repositoryToken" />
<result column="repository_user_name" jdbcType="VARCHAR" property="repositoryUserName" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.FileModule">
<result column="repository_desc" jdbcType="LONGVARCHAR" property="repositoryDesc" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -71,8 +78,28 @@
</where>
</sql>
<sql id="Base_Column_List">
id, project_id, `name`, parent_id, `level`, create_time, update_time, pos, create_user
id, project_id, `name`, parent_id, `level`, create_time, update_time, pos, create_user,
module_type, repository_path, repository_token, repository_user_name
</sql>
<sql id="Blob_Column_List">
repository_desc
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.FileModuleExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from file_module
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByExample" parameterType="io.metersphere.base.domain.FileModuleExample" resultMap="BaseResultMap">
select
<if test="distinct">
@ -87,9 +114,11 @@
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from file_module
where id = #{id,jdbcType=VARCHAR}
</select>
@ -106,12 +135,14 @@
<insert id="insert" parameterType="io.metersphere.base.domain.FileModule">
insert into file_module (id, project_id, `name`,
parent_id, `level`, create_time,
update_time, pos, create_user
)
update_time, pos, create_user,
module_type, repository_path, repository_token,
repository_user_name, repository_desc)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{parentId,jdbcType=VARCHAR}, #{level,jdbcType=INTEGER}, #{createTime,jdbcType=BIGINT},
#{updateTime,jdbcType=BIGINT}, #{pos,jdbcType=DOUBLE}, #{createUser,jdbcType=VARCHAR}
)
#{updateTime,jdbcType=BIGINT}, #{pos,jdbcType=DOUBLE}, #{createUser,jdbcType=VARCHAR},
#{moduleType,jdbcType=VARCHAR}, #{repositoryPath,jdbcType=VARCHAR}, #{repositoryToken,jdbcType=VARCHAR},
#{repositoryUserName,jdbcType=VARCHAR}, #{repositoryDesc,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.FileModule">
insert into file_module
@ -143,6 +174,21 @@
<if test="createUser != null">
create_user,
</if>
<if test="moduleType != null">
module_type,
</if>
<if test="repositoryPath != null">
repository_path,
</if>
<if test="repositoryToken != null">
repository_token,
</if>
<if test="repositoryUserName != null">
repository_user_name,
</if>
<if test="repositoryDesc != null">
repository_desc,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -172,6 +218,21 @@
<if test="createUser != null">
#{createUser,jdbcType=VARCHAR},
</if>
<if test="moduleType != null">
#{moduleType,jdbcType=VARCHAR},
</if>
<if test="repositoryPath != null">
#{repositoryPath,jdbcType=VARCHAR},
</if>
<if test="repositoryToken != null">
#{repositoryToken,jdbcType=VARCHAR},
</if>
<if test="repositoryUserName != null">
#{repositoryUserName,jdbcType=VARCHAR},
</if>
<if test="repositoryDesc != null">
#{repositoryDesc,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.FileModuleExample" resultType="java.lang.Long">
@ -210,11 +271,46 @@
<if test="record.createUser != null">
create_user = #{record.createUser,jdbcType=VARCHAR},
</if>
<if test="record.moduleType != null">
module_type = #{record.moduleType,jdbcType=VARCHAR},
</if>
<if test="record.repositoryPath != null">
repository_path = #{record.repositoryPath,jdbcType=VARCHAR},
</if>
<if test="record.repositoryToken != null">
repository_token = #{record.repositoryToken,jdbcType=VARCHAR},
</if>
<if test="record.repositoryUserName != null">
repository_user_name = #{record.repositoryUserName,jdbcType=VARCHAR},
</if>
<if test="record.repositoryDesc != null">
repository_desc = #{record.repositoryDesc,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update file_module
set id = #{record.id,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
parent_id = #{record.parentId,jdbcType=VARCHAR},
`level` = #{record.level,jdbcType=INTEGER},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
pos = #{record.pos,jdbcType=DOUBLE},
create_user = #{record.createUser,jdbcType=VARCHAR},
module_type = #{record.moduleType,jdbcType=VARCHAR},
repository_path = #{record.repositoryPath,jdbcType=VARCHAR},
repository_token = #{record.repositoryToken,jdbcType=VARCHAR},
repository_user_name = #{record.repositoryUserName,jdbcType=VARCHAR},
repository_desc = #{record.repositoryDesc,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update file_module
set id = #{record.id,jdbcType=VARCHAR},
@ -225,7 +321,11 @@
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
pos = #{record.pos,jdbcType=DOUBLE},
create_user = #{record.createUser,jdbcType=VARCHAR}
create_user = #{record.createUser,jdbcType=VARCHAR},
module_type = #{record.moduleType,jdbcType=VARCHAR},
repository_path = #{record.repositoryPath,jdbcType=VARCHAR},
repository_token = #{record.repositoryToken,jdbcType=VARCHAR},
repository_user_name = #{record.repositoryUserName,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -257,9 +357,41 @@
<if test="createUser != null">
create_user = #{createUser,jdbcType=VARCHAR},
</if>
<if test="moduleType != null">
module_type = #{moduleType,jdbcType=VARCHAR},
</if>
<if test="repositoryPath != null">
repository_path = #{repositoryPath,jdbcType=VARCHAR},
</if>
<if test="repositoryToken != null">
repository_token = #{repositoryToken,jdbcType=VARCHAR},
</if>
<if test="repositoryUserName != null">
repository_user_name = #{repositoryUserName,jdbcType=VARCHAR},
</if>
<if test="repositoryDesc != null">
repository_desc = #{repositoryDesc,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.FileModule">
update file_module
set project_id = #{projectId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
parent_id = #{parentId,jdbcType=VARCHAR},
`level` = #{level,jdbcType=INTEGER},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
pos = #{pos,jdbcType=DOUBLE},
create_user = #{createUser,jdbcType=VARCHAR},
module_type = #{moduleType,jdbcType=VARCHAR},
repository_path = #{repositoryPath,jdbcType=VARCHAR},
repository_token = #{repositoryToken,jdbcType=VARCHAR},
repository_user_name = #{repositoryUserName,jdbcType=VARCHAR},
repository_desc = #{repositoryDesc,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.FileModule">
update file_module
set project_id = #{projectId,jdbcType=VARCHAR},
@ -269,7 +401,11 @@
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
pos = #{pos,jdbcType=DOUBLE},
create_user = #{createUser,jdbcType=VARCHAR}
create_user = #{createUser,jdbcType=VARCHAR},
module_type = #{moduleType,jdbcType=VARCHAR},
repository_path = #{repositoryPath,jdbcType=VARCHAR},
repository_token = #{repositoryToken,jdbcType=VARCHAR},
repository_user_name = #{repositoryUserName,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -1,6 +1,6 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.FileMetadataWithBLOBs;
import io.metersphere.metadata.vo.MoveFIleMetadataRequest;
import io.metersphere.performance.request.QueryProjectFileRequest;
import org.apache.ibatis.annotations.Param;
@ -9,7 +9,7 @@ import java.util.List;
import java.util.Map;
public interface ExtFileMetadataMapper {
List<FileMetadata> getProjectFiles(@Param("projectId") String projectId, @Param("request") QueryProjectFileRequest request);
List<FileMetadataWithBLOBs> getProjectFiles(@Param("projectId") String projectId, @Param("request") QueryProjectFileRequest request);
List<String> getTypes();
@ -17,5 +17,7 @@ public interface ExtFileMetadataMapper {
List<Map<String, Object>> moduleCountByMetadataIds(@Param("ids") List<String> ids);
void updateModuleIdByProjectId(@Param("moduleId")String moduleId, @Param("projectId")String projectId);
void updateModuleIdByProjectId(@Param("moduleId") String moduleId, @Param("projectId") String projectId);
List<String> selectRefIdsByIds(@Param("ids") List<String> nodeIds);
}

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.ext.ExtFileMetadataMapper">
<select id="getProjectFiles" resultType="io.metersphere.base.domain.FileMetadata">
<select id="getProjectFiles" resultType="io.metersphere.base.domain.FileMetadataWithBLOBs">
SELECT file_metadata.* FROM file_metadata
WHERE project_id = #{projectId,jdbcType=VARCHAR} AND type != 'RSA_KEY'
WHERE project_id = #{projectId,jdbcType=VARCHAR} AND type != 'RSA_KEY' AND latest IS TRUE
<if test="request.name != null and request.name !=''">
AND ( file_metadata.name LIKE CONCAT('%', #{request.name}, '%')
OR file_metadata.tags LIKE CONCAT('%', #{request.name}, '%')
@ -69,7 +69,7 @@
<update id="move">
update file_metadata set module_id = #{request.moduleId}
where id in
where storage != 'GIT' AND id in
<foreach collection="request.metadataIds" item="value" separator="," open="(" close=")">
#{value}
</foreach>
@ -83,6 +83,15 @@
</foreach>
GROUP BY module_id
</select>
<select id="selectRefIdsByIds" resultType="java.util.Map">
select ref_id from file_metadata
where ref_id IS NOT NULL AND id in
<foreach collection="ids" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</select>
<update id="updateModuleIdByProjectId">
update file_metadata set module_id = #{moduleId}
where project_id = #{projectId} and module_id is null

View File

@ -10,6 +10,7 @@
#{emp.updateTime,jdbcType=BIGINT})
</foreach>
</insert>
<select id="getNodeTreeByProjectId" resultType="io.metersphere.metadata.vo.FileModuleVo">
select
<include refid="io.metersphere.base.mapper.FileModuleMapper.Base_Column_List"/>

View File

@ -0,0 +1,20 @@
package io.metersphere.commons.constants;
public enum FileModuleTypeConstants {
MODULE("module"),REPOSITORY("repository");
private String value;
FileModuleTypeConstants(String value) {
this.value = value;
}
@Override
public String toString() {
return this.value;
}
public String getValue() {
return this.value;
}
}

View File

@ -1,5 +1,5 @@
package io.metersphere.commons.constants;
public enum StorageConstants {
LOCAL, MINIO, FILE_REF
LOCAL, MINIO, FILE_REF, GIT
}

View File

@ -3,8 +3,10 @@ package io.metersphere.commons.utils;
import io.metersphere.api.dto.scenario.request.BodyFile;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.JarConfig;
import io.metersphere.commons.constants.StorageConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.i18n.Translator;
import io.metersphere.metadata.service.FileMetadataService;
import io.metersphere.service.JarConfigService;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections.CollectionUtils;
@ -52,6 +54,33 @@ public class FileUtils {
return new byte[10];
}
public static void createFile(String filePath, byte[] fileBytes) {
File file = new File(filePath);
if (file.exists()) {
file.delete();
}
try {
File dir = file.getParentFile();
if (!dir.exists()) {
dir.mkdirs();
}
file.createNewFile();
} catch (Exception e) {
LogUtil.error(e);
}
try (InputStream in = new ByteArrayInputStream(fileBytes); OutputStream out = new FileOutputStream(file)) {
final int MAX = 4096;
byte[] buf = new byte[MAX];
for (int bytesRead = in.read(buf, 0, MAX); bytesRead != -1; bytesRead = in.read(buf, 0, MAX)) {
out.write(buf, 0, bytesRead);
}
} catch (IOException e) {
LogUtil.error(e);
MSException.throwException(Translator.get("upload_fail"));
}
}
private static void create(List<String> bodyUploadIds, List<MultipartFile> bodyFiles, String path) {
String filePath = BODY_FILE_DIR;
if (StringUtils.isNotEmpty(path)) {
@ -123,7 +152,7 @@ public class FileUtils {
});
}
}
public static void copyBodyFiles(String sourceId, String targetId) {
try {
String sourcePath = BODY_FILE_DIR + File.separator + sourceId;
@ -309,6 +338,10 @@ public class FileUtils {
BodyFile file = new BodyFile();
file.setId(arg.getParamName());
file.setName(arg.getPath());
if (arg.getPropertyAsBoolean("isRef")) {
file.setStorage(StorageConstants.FILE_REF.name());
file.setFileId(arg.getPropertyAsString("fileId"));
}
files.add(file);
}
}
@ -327,6 +360,58 @@ public class FileUtils {
}
}
/**
* 获取当前jmx 涉及到的文件 执行时
*
* @param tree
*/
public static void getExecuteFiles(HashTree tree, String reportId, List<BodyFile> files) {
FileMetadataService fileMetadataService = CommonBeanFactory.getBean(FileMetadataService.class);
for (Object key : tree.keySet()) {
HashTree node = tree.get(key);
if (key instanceof HTTPSamplerProxy) {
HTTPSamplerProxy source = (HTTPSamplerProxy) key;
if (source != null && source.getHTTPFiles().length > 0) {
for (HTTPFileArg arg : source.getHTTPFiles()) {
BodyFile file = new BodyFile();
file.setId(arg.getParamName());
file.setName(arg.getPath());
if (arg.getPropertyAsBoolean("isRef") && fileMetadataService != null) {
FileMetadata fileMetadata = fileMetadataService.getFileMetadataById(arg.getPropertyAsString("fileId"));
if (fileMetadata != null && StringUtils.equals(StorageConstants.GIT.name(), fileMetadata.getStorage())) {
file.setStorage(StorageConstants.GIT.name());
file.setFileId(arg.getPropertyAsString("fileId"));
file.setName(reportId + File.separator + fileMetadata.getName());
arg.setPath(BODY_FILE_DIR + File.separator + reportId + File.separator + fileMetadata.getName());
}
}
files.add(file);
}
}
} else if (key instanceof CSVDataSet) {
CSVDataSet source = (CSVDataSet) key;
if (source != null && StringUtils.isNotEmpty(source.getPropertyAsString("filename"))) {
BodyFile file = new BodyFile();
file.setId(source.getPropertyAsString("filename"));
file.setName(source.getPropertyAsString("filename"));
if (source.getPropertyAsBoolean("isRef") && fileMetadataService != null) {
FileMetadata fileMetadata = fileMetadataService.getFileMetadataById(source.getPropertyAsString("fileId"));
if (fileMetadata != null && StringUtils.equals(StorageConstants.GIT.name(), fileMetadata.getStorage())) {
file.setStorage(StorageConstants.GIT.name());
file.setFileId(source.getPropertyAsString("fileId"));
file.setName(reportId + File.separator + fileMetadata.getName());
source.setFilename(BODY_FILE_DIR + File.separator + reportId + File.separator + fileMetadata.getName());
}
}
files.add(file);
}
}
if (node != null) {
getExecuteFiles(node, reportId, files);
}
}
}
public static byte[] fileToByte(File tradeFile) {
byte[] buffer = null;
try (FileInputStream fis = new FileInputStream(tradeFile);
@ -392,6 +477,44 @@ public class FileUtils {
return buffer;
}
public static List<FileMetadata> getRepositoryFileMetadata(HashTree tree) {
FileMetadataService fileMetadataService = CommonBeanFactory.getBean(FileMetadataService.class);
List<FileMetadata> list = new ArrayList<>();
for (Object key : tree.keySet()) {
HashTree node = tree.get(key);
if (key instanceof HTTPSamplerProxy) {
HTTPSamplerProxy source = (HTTPSamplerProxy) key;
if (source != null && source.getHTTPFiles().length > 0) {
for (HTTPFileArg arg : source.getHTTPFiles()) {
if (arg.getPropertyAsBoolean("isRef") && fileMetadataService != null) {
FileMetadata fileMetadata = fileMetadataService.getFileMetadataById(arg.getPropertyAsString("fileId"));
if (fileMetadata != null && StringUtils.equals(StorageConstants.GIT.name(), fileMetadata.getStorage())) {
list.add(fileMetadata);
arg.setPath(fileMetadata.getName());
arg.setName(fileMetadata.getName());
}
}
}
}
} else if (key instanceof CSVDataSet) {
CSVDataSet source = (CSVDataSet) key;
if (source != null && StringUtils.isNotEmpty(source.getPropertyAsString("filename"))) {
if (source.getPropertyAsBoolean("isRef") && fileMetadataService != null) {
FileMetadata fileMetadata = fileMetadataService.getFileMetadataById(source.getPropertyAsString("fileId"));
if (fileMetadata != null && StringUtils.equals(StorageConstants.GIT.name(), fileMetadata.getStorage())) {
list.add(fileMetadata);
source.setFilename(fileMetadata.getName());
}
}
}
}
if (node != null) {
list.addAll(getRepositoryFileMetadata(node));
}
}
return list;
}
public List<Object> getZipJar() {
List<Object> jarFiles = new LinkedList<>();
// jar

View File

@ -13,9 +13,14 @@ import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.assertions.MsAssertionRegex;
import io.metersphere.api.dto.definition.request.assertions.MsAssertions;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.request.BodyFile;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.api.service.ExtErrorReportLibraryService;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.commons.constants.StorageConstants;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.metadata.service.FileMetadataService;
import io.metersphere.metadata.vo.repository.FileInfoDTO;
import io.metersphere.plugin.core.MsTestElement;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@ -26,6 +31,7 @@ import org.apache.jmeter.modifiers.JSR223PreProcessor;
import org.apache.jmeter.protocol.java.sampler.JSR223Sampler;
import org.apache.jorphan.collections.HashTree;
import java.io.File;
import java.util.*;
/**
@ -34,6 +40,39 @@ import java.util.*;
*/
public class HashTreeUtil {
public static void initRepositoryFiles(JmeterRunRequestDTO runRequest) {
if (runRequest.getPool().isPool() || runRequest.getPool().isK8s()) {
return;
}
List<BodyFile> files = new LinkedList<>();
FileUtils.getExecuteFiles(runRequest.getHashTree(), runRequest.getReportId(), files);
if (CollectionUtils.isNotEmpty(files)) {
Map<String, String> repositoryFileMap = new HashMap<>();
for (BodyFile bodyFile : files) {
if (StringUtils.equals(bodyFile.getStorage(), StorageConstants.GIT.name())
&& StringUtils.isNotBlank(bodyFile.getFileId())) {
repositoryFileMap.put(bodyFile.getFileId(), bodyFile.getName());
}
}
FileMetadataService fileMetadataService = CommonBeanFactory.getBean(FileMetadataService.class);
if (fileMetadataService != null) {
Map<String, byte[]> multipartFiles = new LinkedHashMap<>();
List<FileInfoDTO> fileInfoDTOList = fileMetadataService.downloadFileByIds(repositoryFileMap.keySet());
fileInfoDTOList.forEach(repositoryFile -> {
if (repositoryFile.getFileByte() != null) {
multipartFiles.put(FileUtils.BODY_FILE_DIR + File.separator + repositoryFileMap.get(repositoryFile.getId()), repositoryFile.getFileByte());
}
});
for (Map.Entry<String, byte[]> fileEntry : multipartFiles.entrySet()) {
String fileName = fileEntry.getKey();
byte[] fileBytes = fileEntry.getValue();
FileUtils.createFile(fileName, fileBytes);
}
}
}
}
public Map<String, Map<String, String>> getEnvParamsDataByHashTree(HashTree hashTree, ApiTestEnvironmentService apiTestEnvironmentService) {
Map<String, Map<String, String>> returnMap = new HashMap<>();
Map<String, List<String>> envParamMap = this.getEnvParamsMapByHashTree(hashTree);
@ -85,7 +124,7 @@ public class HashTreeUtil {
return returnMap;
}
public void setEnvParamsMapToHashTree(HashTree hashTree, Map<String, Map<String, String>> envParamsMap) {
public void setEnvParamsMapToHashTree(HashTree hashTree, Map<String, Map<String, String>> envParamsMap) {
if (hashTree != null) {
Map<String, String> allParamMap = new HashMap<>();
for (Map<String, String> paramMap : envParamsMap.values()) {
@ -239,9 +278,9 @@ public class HashTreeUtil {
return target;
}
public static List<MsAssertions> getErrorReportByProjectId(String projectId,boolean higherThanSuccess,boolean higherThanError) {
public static List<MsAssertions> getErrorReportByProjectId(String projectId, boolean higherThanSuccess, boolean higherThanError) {
ExtErrorReportLibraryService service = CommonBeanFactory.getBean(ExtErrorReportLibraryService.class);
return service.getAssertionByProjectIdAndStatusIsOpen(projectId,higherThanSuccess,higherThanError);
return service.getAssertionByProjectIdAndStatusIsOpen(projectId, higherThanSuccess, higherThanError);
}
public static void addPositive(EnvironmentConfig envConfig, HashTree samplerHashTree, ParameterConfig config, String projectId) {
@ -249,7 +288,7 @@ public class HashTreeUtil {
return;
}
if (!config.isOperating() && envConfig.isUseErrorCode()) {
List<MsAssertions> errorReportAssertion = HashTreeUtil.getErrorReportByProjectId(projectId,envConfig.isHigherThanSuccess(),envConfig.isHigherThanError());
List<MsAssertions> errorReportAssertion = HashTreeUtil.getErrorReportByProjectId(projectId, envConfig.isHigherThanSuccess(), envConfig.isHigherThanError());
for (MsAssertions assertion : errorReportAssertion) {
assertion.toHashTree(samplerHashTree, assertion.getHashTree(), config);
}
@ -266,7 +305,8 @@ public class HashTreeUtil {
JSONObject element = JSON.parseObject(scenarioDefinition, Feature.DisableSpecialKeyDetect);
ElementUtil.dataFormatting(element);
try {
return mapper.readValue(element.getString("hashTree"), new TypeReference<>() {});
return mapper.readValue(element.getString("hashTree"), new TypeReference<>() {
});
} catch (JsonProcessingException e) {
e.printStackTrace();
}

View File

@ -3,6 +3,7 @@ package io.metersphere.metadata.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.FileMetadataWithBLOBs;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.OperLogModule;
import io.metersphere.commons.utils.PageUtils;
@ -11,7 +12,10 @@ import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.metadata.service.FileMetadataService;
import io.metersphere.metadata.vo.DownloadRequest;
import io.metersphere.metadata.vo.DumpFileRequest;
import io.metersphere.metadata.vo.FileMetadataCreateRequest;
import io.metersphere.metadata.vo.MoveFIleMetadataRequest;
import io.metersphere.metadata.vo.repository.FileRelevanceCaseDTO;
import io.metersphere.metadata.vo.repository.FileVersionDTO;
import io.metersphere.performance.request.QueryProjectFileRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
@ -34,21 +38,27 @@ public class FileMetadataController {
}
@PostMapping("/project/{projectId}/{goPage}/{pageSize}")
public Pager<List<FileMetadata>> getProjectFiles(@PathVariable String projectId,
@PathVariable int goPage, @PathVariable int pageSize,
@RequestBody QueryProjectFileRequest request) {
public Pager<List<FileMetadataWithBLOBs>> getProjectFiles(@PathVariable String projectId,
@PathVariable int goPage, @PathVariable int pageSize,
@RequestBody QueryProjectFileRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, fileMetadataService.getProjectFiles(projectId, request));
}
@PostMapping(value = "/create")
@MsAuditLog(module = OperLogModule.PROJECT_FILE_MANAGEMENT, type = OperLogConstants.CREATE, title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = FileMetadataService.class)
public List<FileMetadata> create(@RequestPart("request") FileMetadata request, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
public List<FileMetadata> create(@RequestPart("request") FileMetadataCreateRequest request, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
return fileMetadataService.create(request, files);
}
@PostMapping(value = "/git/pull")
@MsAuditLog(module = OperLogModule.PROJECT_FILE_MANAGEMENT, type = OperLogConstants.CREATE, title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = FileMetadataService.class)
public FileMetadata pullFromRepository(@RequestPart("request") FileMetadata request) {
return fileMetadataService.pullFromRepository(request);
}
@PostMapping(value = "/upload")
public FileMetadata upload(@RequestPart("request") FileMetadata request, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
public FileMetadata upload(@RequestPart("request") FileMetadataWithBLOBs request, @RequestPart(value = "file", required = false) List<MultipartFile> files) {
return fileMetadataService.reLoad(request, files);
}
@ -94,7 +104,7 @@ public class FileMetadataController {
@PostMapping(value = "/update")
@MsAuditLog(module = OperLogModule.PROJECT_FILE_MANAGEMENT, type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#request.id)", title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = FileMetadataService.class)
public void update(@RequestBody FileMetadata request) {
public void update(@RequestBody FileMetadataWithBLOBs request) {
fileMetadataService.update(request);
}
@ -117,4 +127,20 @@ public class FileMetadataController {
public List<String> exist(@RequestBody List<String> fileIds) {
return fileMetadataService.exists(fileIds);
}
@GetMapping(value = "/fileVersion/{refId}")
public List<FileVersionDTO> selectFileVersion(@PathVariable String refId) {
return fileMetadataService.selectFileVersion(refId);
}
@PostMapping("/file/relevance/case/{refId}/{goPage}/{pageSize}")
public Pager<List<FileRelevanceCaseDTO>> getFileRelevanceCase(@PathVariable String refId, @PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryProjectFileRequest request) {
return fileMetadataService.getFileRelevanceCase(refId, goPage, pageSize);
}
@PostMapping("/case/version/update/{refId}")
public String updateCaseVersion(@PathVariable String refId, @RequestBody QueryProjectFileRequest request) {
return fileMetadataService.updateCaseVersion(refId, request);
}
}

View File

@ -1,13 +1,16 @@
package io.metersphere.metadata.controller;
import io.metersphere.base.domain.FileModule;
import io.metersphere.commons.constants.FileModuleTypeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.OperLogModule;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.metadata.service.FileModuleService;
import io.metersphere.metadata.utils.GitRepositoryUtils;
import io.metersphere.metadata.vo.DragFileModuleRequest;
import io.metersphere.metadata.vo.FileModuleVo;
import io.metersphere.service.CheckPermissionService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@ -34,6 +37,15 @@ public class FileModuleController {
return fileModuleService.addNode(node);
}
@PostMapping("/connect")
public String connect(@RequestBody FileModule node) {
if (StringUtils.equalsIgnoreCase(node.getModuleType(),FileModuleTypeConstants.REPOSITORY.getValue())){
GitRepositoryUtils utils = new GitRepositoryUtils(node.getRepositoryPath(),node.getRepositoryUserName(),node.getRepositoryToken());
utils.getBranches();
}
return "suucess";
}
@PostMapping("/edit")
@MsAuditLog(module = OperLogModule.PROJECT_FILE_MANAGEMENT, type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#node)", title = "#node.name", content = "#msClass.getLogDetails(#node)", msClass = FileModuleService.class)
public int editNode(@RequestBody DragFileModuleRequest node) {

View File

@ -1,9 +1,11 @@
package io.metersphere.metadata.repository;
import io.metersphere.metadata.vo.FileRequest;
import io.metersphere.metadata.vo.repository.FileInfoDTO;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
public interface FileRepository {
String saveFile(MultipartFile file, FileRequest request) throws IOException;
@ -14,6 +16,8 @@ public interface FileRepository {
byte[] getFile(FileRequest request) throws Exception;
List<FileInfoDTO> getFileBatch(List<FileRequest> requestList) throws Exception;
boolean reName(FileRequest request) throws Exception;
}

View File

@ -0,0 +1,101 @@
package io.metersphere.metadata.repository;
import io.metersphere.commons.constants.StorageConstants;
import io.metersphere.metadata.utils.GitRepositoryUtils;
import io.metersphere.metadata.utils.MetadataUtils;
import io.metersphere.metadata.vo.FileRequest;
import io.metersphere.metadata.vo.repository.FileInfoDTO;
import io.metersphere.metadata.vo.repository.GitFileAttachInfo;
import io.metersphere.metadata.vo.repository.RepositoryRequest;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GitFileRepository implements FileRepository {
@Override
public String saveFile(MultipartFile multipartFile, FileRequest request) throws IOException {
return null;
}
@Override
public String saveFile(byte[] bytes, FileRequest request) throws IOException {
return null;
}
@Override
public void delete(FileRequest request) throws Exception {
}
@Override
public byte[] getFile(FileRequest request) throws Exception {
byte[] buffer = new byte[0];
if (request.getFileAttachInfo() != null && request.getFileAttachInfo() instanceof GitFileAttachInfo) {
GitFileAttachInfo gitFileInfo = (GitFileAttachInfo) request.getFileAttachInfo();
GitRepositoryUtils repositoryUtils = new GitRepositoryUtils(
gitFileInfo.getRepositoryPath(), gitFileInfo.getUserName(), gitFileInfo.getToken());
buffer = repositoryUtils.getSingleFile(gitFileInfo.getFilePath(), gitFileInfo.getCommitId());
}
return buffer;
}
@Override
public List<FileInfoDTO> getFileBatch(List<FileRequest> allRequests) throws Exception {
List<FileInfoDTO> list = new ArrayList<>();
if (CollectionUtils.isNotEmpty(allRequests)) {
Map<String, List<FileRequest>> requestGroupByRepository = new HashMap<>();
for (FileRequest request : allRequests) {
if (request.getFileAttachInfo() != null && request.getFileAttachInfo() instanceof GitFileAttachInfo) {
GitFileAttachInfo gitFileInfo = (GitFileAttachInfo) request.getFileAttachInfo();
if (requestGroupByRepository.containsKey(gitFileInfo.getRepositoryInfo())) {
requestGroupByRepository.get(gitFileInfo.getRepositoryInfo()).add(request);
} else {
requestGroupByRepository.put(gitFileInfo.getRepositoryInfo(), new ArrayList<>() {{
this.add(request);
}});
}
}
}
for (Map.Entry<String, List<FileRequest>> entry : requestGroupByRepository.entrySet()) {
List<FileRequest> requestList = entry.getValue();
GitFileAttachInfo baseGitFileInfo = null;
List<RepositoryRequest> repositoryRequestList = new ArrayList<>();
for (FileRequest fileRequest : requestList) {
GitFileAttachInfo gitFileInfo = (GitFileAttachInfo) fileRequest.getFileAttachInfo();
if (baseGitFileInfo == null) {
baseGitFileInfo = gitFileInfo;
}
repositoryRequestList.add(new RepositoryRequest() {{
this.setCommitId(gitFileInfo.getCommitId());
this.setFilePath(gitFileInfo.getFilePath());
this.setFileMetadataId(fileRequest.getResourceId());
}});
}
GitRepositoryUtils repositoryUtils = new GitRepositoryUtils(
baseGitFileInfo.getRepositoryPath(), baseGitFileInfo.getUserName(), baseGitFileInfo.getToken());
Map<String, byte[]> fileByteMap = repositoryUtils.getFiles(repositoryRequestList);
repositoryRequestList.forEach(repositoryFile -> {
if (fileByteMap.get(repositoryFile.getFileMetadataId()) != null) {
FileInfoDTO repositoryFileDTO = new FileInfoDTO(
repositoryFile.getFileMetadataId(), MetadataUtils.getFileNameByRemotePath(repositoryFile.getFilePath()), StorageConstants.GIT.name(), fileByteMap.get(repositoryFile.getFileMetadataId()));
list.add(repositoryFileDTO);
}
});
}
}
return list;
}
@Override
public boolean reName(FileRequest request) throws Exception {
return false;
}
}

View File

@ -5,11 +5,15 @@ import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.i18n.Translator;
import io.metersphere.metadata.vo.FileRequest;
import io.metersphere.metadata.vo.repository.FileInfoDTO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.util.FileUtil;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class LocalFileRepository implements FileRepository {
@Override
@ -80,6 +84,18 @@ public class LocalFileRepository implements FileRepository {
return buffer;
}
@Override
public List<FileInfoDTO> getFileBatch(List<FileRequest> requestList) throws Exception {
List<FileInfoDTO> list = new ArrayList<>();
if (CollectionUtils.isNotEmpty(requestList)) {
for (FileRequest fileRequest : requestList) {
FileInfoDTO fileInfoDTO = new FileInfoDTO(fileRequest.getResourceId(), fileRequest.getFileName(), fileRequest.getStorage(), this.getFile(fileRequest));
list.add(fileInfoDTO);
}
}
return list;
}
@Override
public boolean reName(FileRequest request) throws Exception {
File file = new File(StringUtils.join(FileUtils.BODY_FILE_DIR, "/", request.getProjectId(), "/", request.getBeforeName()));

View File

@ -1,9 +1,13 @@
package io.metersphere.metadata.repository;
import io.metersphere.metadata.vo.FileRequest;
import io.metersphere.metadata.vo.repository.FileInfoDTO;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MinIOFileRepository implements FileRepository {
@ -27,6 +31,18 @@ public class MinIOFileRepository implements FileRepository {
return new byte[0];
}
@Override
public List<FileInfoDTO> getFileBatch(List<FileRequest> requestList) throws Exception {
List<FileInfoDTO> list = new ArrayList<>();
if (CollectionUtils.isNotEmpty(requestList)) {
for (FileRequest fileRequest : requestList) {
FileInfoDTO fileInfoDTO = new FileInfoDTO(fileRequest.getResourceId(), fileRequest.getFileName(), fileRequest.getStorage(), this.getFile(fileRequest));
list.add(fileInfoDTO);
}
}
return list;
}
@Override
public boolean reName(FileRequest request) throws Exception {
return false;

View File

@ -3,6 +3,7 @@ package io.metersphere.metadata.service;
import io.metersphere.commons.constants.StorageConstants;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.metadata.repository.FileRepository;
import io.metersphere.metadata.repository.GitFileRepository;
import io.metersphere.metadata.repository.LocalFileRepository;
import org.apache.commons.lang3.StringUtils;
@ -11,6 +12,9 @@ public class FileCenter {
if (StringUtils.equals(StorageConstants.MINIO.name(), storage)) {
LogUtil.info("NAS文件处理");
return null;
} else if (StringUtils.equals(StorageConstants.GIT.name(), storage)) {
LogUtil.info("Git文件处理");
return new GitFileRepository();
} else {
LogUtil.info("LOCAL文件处理");
return new LocalFileRepository();

View File

@ -3,11 +3,17 @@ package io.metersphere.metadata.service;
import io.metersphere.commons.constants.StorageConstants;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.metadata.vo.FileRequest;
import io.metersphere.metadata.vo.repository.FileInfoDTO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class FileManagerService {
@ -79,4 +85,20 @@ public class FileManagerService {
return null;
}
}
public List<FileInfoDTO> downloadFileBatch(List<FileRequest> requestList) {
List<FileInfoDTO> list = new ArrayList<>();
if (CollectionUtils.isNotEmpty(requestList)) {
Map<String, List<FileRequest>> requestByStorage = requestList.stream().collect(Collectors.groupingBy(FileRequest::getStorage));
for (Map.Entry<String, List<FileRequest>> requestByStorageEntry : requestByStorage.entrySet()) {
try {
list.addAll(FileCenter.getRepository(requestByStorageEntry.getKey()).getFileBatch(requestByStorageEntry.getValue()));
} catch (Exception e) {
LogUtil.error(e);
return null;
}
}
}
return list;
}
}

View File

@ -1,33 +1,40 @@
package io.metersphere.metadata.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.ByteUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtFileMetadataMapper;
import io.metersphere.commons.constants.ApiTestConstants;
import io.metersphere.commons.constants.FileAssociationType;
import io.metersphere.commons.constants.FileModuleTypeConstants;
import io.metersphere.commons.constants.StorageConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.OrderRequest;
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.system.SystemReference;
import io.metersphere.metadata.utils.GitRepositoryUtils;
import io.metersphere.metadata.utils.MetadataUtils;
import io.metersphere.metadata.vo.DownloadRequest;
import io.metersphere.metadata.vo.DumpFileRequest;
import io.metersphere.metadata.vo.FileRequest;
import io.metersphere.metadata.vo.MoveFIleMetadataRequest;
import io.metersphere.metadata.vo.*;
import io.metersphere.metadata.vo.repository.FileInfoDTO;
import io.metersphere.metadata.vo.repository.FileRelevanceCaseDTO;
import io.metersphere.metadata.vo.repository.FileVersionDTO;
import io.metersphere.metadata.vo.repository.GitFileAttachInfo;
import io.metersphere.performance.request.QueryProjectFileRequest;
import io.metersphere.service.UserService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
@ -53,24 +60,75 @@ public class FileMetadataService {
private FileContentMapper fileContentMapper;
@Resource
private FileAssociationMapper fileAssociationMapper;
@Resource
private UserService userService;
@Resource
private ApiDefinitionMapper apiDefinitionMapper;
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private ApiScenarioMapper apiScenarioMapper;
@Resource
private TestCaseMapper testCaseMapper;
public List<FileMetadata> create(FileMetadata fileMetadata, List<MultipartFile> files) {
public List<FileMetadata> create(FileMetadataCreateRequest fileMetadata, List<MultipartFile> files) {
List<FileMetadata> result = new ArrayList<>();
if (fileMetadata == null) {
fileMetadata = new FileMetadata();
fileMetadata = new FileMetadataCreateRequest();
}
if (!CollectionUtils.isEmpty(files)) {
if (StringUtils.equals(StorageConstants.GIT.name(), fileMetadata.getStorage())) {
fileMetadata.setPath(StringUtils.trim(fileMetadata.getPath()));
this.validateGitFile(fileMetadata);
FileModule fileModule = fileModuleService.get(fileMetadata.getModuleId());
GitRepositoryUtils repositoryUtils = new GitRepositoryUtils(
fileModule.getRepositoryPath(), fileModule.getRepositoryUserName(), fileModule.getRepositoryToken());
GitFileAttachInfo gitFileInfo = repositoryUtils.selectLastCommitIdByBranch(fileMetadata.getRepositoryBranch(), fileMetadata.getRepositoryPath());
if (gitFileInfo != null) {
fileMetadata.setName(MetadataUtils.getFileNameByRemotePath(fileMetadata.getRepositoryPath()));
fileMetadata.setType(MetadataUtils.getFileType(fileMetadata.getRepositoryPath()));
fileMetadata.setPath(fileMetadata.getRepositoryPath());
fileMetadata.setSize(Long.valueOf(0));
fileMetadata.setAttachInfo(JSONObject.toJSONString(gitFileInfo));
result.add(this.save(fileMetadata));
} else {
MSException.throwException("File not found!");
}
} else if (!CollectionUtils.isEmpty(files)) {
for (MultipartFile file : files) {
QueryProjectFileRequest request = new QueryProjectFileRequest();
request.setName(file.getOriginalFilename());
result.add(this.saveFile(file, fileMetadata));
}
}
return result;
}
public FileMetadata saveFile(MultipartFile file, FileMetadata fileMetadata) {
private void validateGitFile(FileMetadataCreateRequest fileMetadata) {
if (StringUtils.isEmpty(fileMetadata.getModuleId())) {
MSException.throwException(Translator.get("test_case_module_not_null"));
} else {
FileMetadataExample example = new FileMetadataExample();
example.createCriteria().andModuleIdEqualTo(fileMetadata.getModuleId())
.andStorageEqualTo(fileMetadata.getStorage())
.andPathEqualTo(fileMetadata.getRepositoryPath())
.andIdNotEqualTo(fileMetadata.getId());
if (fileMetadataMapper.countByExample(example) > 0) {
MSException.throwException(Translator.get("project_file_already_exists"));
}
}
}
public FileMetadata save(FileMetadataWithBLOBs fileMetadata) {
long createTime = System.currentTimeMillis();
fileMetadata.setCreateTime(createTime);
fileMetadata.setUpdateTime(createTime);
fileMetadata.setLatest(true);
fileMetadata.setRefId(fileMetadata.getId());
fileMetadataMapper.insert(fileMetadata);
return fileMetadata;
}
public FileMetadata saveFile(MultipartFile file, FileMetadataWithBLOBs fileMetadata) {
this.initBase(fileMetadata);
if (StringUtils.isEmpty(fileMetadata.getName())) {
fileMetadata.setName(file.getOriginalFilename());
@ -84,6 +142,8 @@ public class FileMetadataService {
String path = fileManagerService.upload(file, request);
fileMetadata.setPath(path);
if (fileMetadataMapper.selectByPrimaryKey(fileMetadata.getId()) == null) {
fileMetadata.setLatest(true);
fileMetadata.setRefId(fileMetadata.getId());
fileMetadataMapper.insert(fileMetadata);
} else {
fileMetadataMapper.updateByPrimaryKeyWithBLOBs(fileMetadata);
@ -94,12 +154,12 @@ public class FileMetadataService {
public FileMetadata saveFile(MultipartFile file, String projectId) {
FileMetadata fileMetadata = new FileMetadata();
FileMetadataWithBLOBs fileMetadata = new FileMetadataWithBLOBs();
fileMetadata.setProjectId(projectId);
return saveFile(file, fileMetadata);
}
public List<FileMetadata> getProjectFiles(String projectId, QueryProjectFileRequest request) {
public List<FileMetadataWithBLOBs> getProjectFiles(String projectId, QueryProjectFileRequest request) {
if (CollectionUtils.isEmpty(request.getOrders())) {
OrderRequest req = new OrderRequest();
req.setName("update_time");
@ -108,7 +168,8 @@ public class FileMetadataService {
this.add(req);
}});
}
return extFileMetadataMapper.getProjectFiles(projectId, request);
List<FileMetadataWithBLOBs> fileMetadataList = extFileMetadataMapper.getProjectFiles(projectId, request);
return fileMetadataList;
}
public void deleteFile(String fileId) {
@ -136,6 +197,14 @@ public class FileMetadataService {
// 删除文件,历史遗留数据保留附件只删除关系
FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId);
fileMetadataMapper.deleteByPrimaryKey(fileId);
if (StringUtils.isNotEmpty(fileMetadata.getRefId())) {
//删除其余版本的文件
FileMetadataExample fileMetadataExample = new FileMetadataExample();
fileMetadataExample.createCriteria().andRefIdEqualTo(fileMetadata.getRefId());
fileMetadataMapper.deleteByExample(fileMetadataExample);
}
if (StringUtils.isNotEmpty(fileMetadata.getStorage()) && StringUtils.isEmpty(fileMetadata.getResourceType())) {
FileRequest request = new FileRequest(fileMetadata.getProjectId(), fileMetadata.getName(), fileMetadata.getType());
fileManagerService.delete(request);
@ -155,8 +224,14 @@ public class FileMetadataService {
}
public void move(MoveFIleMetadataRequest request) {
if (!CollectionUtils.isEmpty(request.getMetadataIds()) && StringUtils.isNotEmpty(request.getModuleId())) {
extFileMetadataMapper.move(request);
//不可移动到存储库模块节点
FileModule fileModule = fileModuleService.get(request.getModuleId());
if (fileModule != null && !CollectionUtils.isEmpty(request.getMetadataIds()) && StringUtils.isNotEmpty(request.getModuleId())) {
if (StringUtils.equals(fileModule.getModuleType(), FileModuleTypeConstants.REPOSITORY.getValue())) {
MSException.throwException(Translator.get("can_not_move_to_repository_node"));
} else {
extFileMetadataMapper.move(request);
}
}
}
@ -169,14 +244,14 @@ public class FileMetadataService {
}
public byte[] loadFileAsBytes(String id) {
FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(id);
FileMetadataWithBLOBs fileMetadata = fileMetadataMapper.selectByPrimaryKey(id);
if (fileMetadata == null) {
return new byte[0];
}
return this.loadFileAsBytes(fileMetadata);
}
private byte[] loadFileAsBytes(FileMetadata fileMetadata) {
private byte[] loadFileAsBytes(FileMetadataWithBLOBs fileMetadata) {
byte[] bytes = new byte[0];
// 兼容历史数据
if (StringUtils.isEmpty(fileMetadata.getStorage()) && StringUtils.isEmpty(fileMetadata.getResourceType())) {
@ -186,6 +261,8 @@ public class FileMetadataService {
FileRequest request = new FileRequest(fileMetadata.getProjectId(), fileMetadata.getName(), fileMetadata.getType());
request.setResourceType(fileMetadata.getResourceType());
request.setPath(fileMetadata.getPath());
request.setStorage(fileMetadata.getStorage());
request.setFileAttachInfoByString(fileMetadata.getAttachInfo());
bytes = fileManagerService.downloadFile(request);
}
return bytes;
@ -193,7 +270,7 @@ public class FileMetadataService {
public ResponseEntity<byte[]> getFile(String fileId) {
MediaType contentType = MediaType.parseMediaType("application/octet-stream");
FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId);
FileMetadataWithBLOBs fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId);
if (fileMetadata == null) {
return null;
}
@ -233,7 +310,7 @@ public class FileMetadataService {
return fileMetadataMapper.selectByPrimaryKey(fileMetadata.getId()).getName();
}
public void update(FileMetadata fileMetadata) {
public void update(FileMetadataWithBLOBs fileMetadata) {
this.checkName(fileMetadata);
String beforeName = getBeforeName(fileMetadata);
if (!StringUtils.equalsIgnoreCase(beforeName, fileMetadata.getName())
@ -252,7 +329,7 @@ public class FileMetadataService {
fileMetadataMapper.updateByPrimaryKeySelective(fileMetadata);
}
public FileMetadata reLoad(FileMetadata fileMetadata, List<MultipartFile> files) {
public FileMetadata reLoad(FileMetadataWithBLOBs fileMetadata, List<MultipartFile> files) {
if (CollectionUtils.isEmpty(files)) {
return fileMetadata;
}
@ -284,7 +361,7 @@ public class FileMetadataService {
public List<FileMetadata> uploadFiles(String projectId, List<MultipartFile> files) {
List<FileMetadata> result = new ArrayList<>();
if (!CollectionUtils.isEmpty(files)) {
FileMetadata fileMetadata = new FileMetadata();
FileMetadataWithBLOBs fileMetadata = new FileMetadataWithBLOBs();
fileMetadata.setProjectId(projectId);
fileMetadata.setStorage(StorageConstants.LOCAL.name());
files.forEach(file -> {
@ -301,7 +378,7 @@ public class FileMetadataService {
}
public FileMetadata updateFile(String fileId, MultipartFile file) {
FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId);
FileMetadataWithBLOBs fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId);
reLoad(fileMetadata, new ArrayList<>() {{
this.add(file);
}});
@ -325,7 +402,7 @@ public class FileMetadataService {
this.saveFile(file);
}
} else {
FileMetadata fileMetadata = new FileMetadata();
FileMetadataCreateRequest fileMetadata = new FileMetadataCreateRequest();
fileMetadata.setProjectId(request.getProjectId());
fileMetadata.setModuleId(request.getModuleId());
this.create(fileMetadata, files);
@ -386,7 +463,7 @@ public class FileMetadataService {
}
public FileMetadata saveFile(byte[] fileByte, String fileName, Long fileSize) {
final FileMetadata fileMetadata = new FileMetadata();
final FileMetadataWithBLOBs fileMetadata = new FileMetadataWithBLOBs();
this.initBase(fileMetadata);
fileMetadata.setName(fileName);
fileMetadata.setSize(fileSize);
@ -396,6 +473,8 @@ public class FileMetadataService {
FileRequest request = new FileRequest(fileMetadata.getProjectId(), fileMetadata.getName(), fileMetadata.getType());
String path = fileManagerService.upload(fileByte, request);
fileMetadata.setPath(path);
fileMetadata.setLatest(true);
fileMetadata.setRefId(fileMetadata.getId());
fileMetadataMapper.insert(fileMetadata);
return fileMetadata;
}
@ -440,4 +519,207 @@ public class FileMetadataService {
List<FileMetadata> fileMetadataList = fileMetadataMapper.selectByExample(example);
return fileMetadataList.stream().map(FileMetadata::getId).collect(Collectors.toList());
}
public List<FileInfoDTO> downloadFileByIds(Collection<String> fileIdList) {
if (CollectionUtils.isEmpty(fileIdList)) {
return new ArrayList<>(0);
}
LogUtil.info(JSONObject.toJSONString(fileIdList) + " 获取文件开始");
FileMetadataExample example = new FileMetadataExample();
example.createCriteria().andIdIn(new ArrayList<>(fileIdList));
List<FileMetadataWithBLOBs> fileMetadataWithBLOBs = fileMetadataMapper.selectByExampleWithBLOBs(example);
List<FileRequest> requestList = new ArrayList<>();
fileMetadataWithBLOBs.forEach(fileMetadata -> {
FileRequest request = new FileRequest(fileMetadata.getProjectId(), fileMetadata.getName(), fileMetadata.getType());
request.setResourceId(fileMetadata.getId());
request.setResourceType(fileMetadata.getResourceType());
request.setPath(fileMetadata.getPath());
request.setStorage(fileMetadata.getStorage());
if (StringUtils.equals(fileMetadata.getStorage(), StorageConstants.GIT.name())) {
try {
GitFileAttachInfo gitFileInfo = JSONObject.parseObject(fileMetadata.getAttachInfo(), GitFileAttachInfo.class);
request.setFileAttachInfo(gitFileInfo);
} catch (Exception e) {
LogUtil.error("解析Git附加信息【" + fileMetadata.getAttachInfo() + "】失败!", e);
}
}
requestList.add(request);
});
List<FileInfoDTO> repositoryFileDTOList = fileManagerService.downloadFileBatch(requestList);
LogUtil.info(JSONObject.toJSONString(fileIdList) + " 获取文件结束。");
return repositoryFileDTOList;
}
public FileMetadata pullFromRepository(FileMetadata request) {
FileMetadata returnModel = null;
FileMetadataWithBLOBs baseMetadata = fileMetadataMapper.selectByPrimaryKey(request.getId());
if (StringUtils.equals(baseMetadata.getStorage(), StorageConstants.GIT.name()) && StringUtils.isNotEmpty(baseMetadata.getAttachInfo())) {
GitFileAttachInfo baseAttachInfo = JSONObject.parseObject(baseMetadata.getAttachInfo(), GitFileAttachInfo.class);
FileModule fileModule = fileModuleService.get(baseMetadata.getModuleId());
if (fileModule != null) {
GitRepositoryUtils repositoryUtils = new GitRepositoryUtils(fileModule.getRepositoryPath(), fileModule.getRepositoryUserName(), fileModule.getRepositoryToken());
GitFileAttachInfo gitFileAttachInfo = repositoryUtils.selectLastCommitIdByBranch(baseAttachInfo.getBranch(), baseAttachInfo.getFilePath());
if (gitFileAttachInfo != null &&
!StringUtils.equals(gitFileAttachInfo.getCommitId(), baseAttachInfo.getCommitId())) {
//有新的commitId更新filemetadata的版本
long thistime = System.currentTimeMillis();
FileMetadataWithBLOBs newMetadata = this.genOtherVersionFileMetadata(baseMetadata, thistime, gitFileAttachInfo);
fileMetadataMapper.insert(newMetadata);
baseMetadata.setUpdateTime(thistime);
baseMetadata.setLatest(false);
baseMetadata.setUpdateUser(SessionUtils.getUserId());
fileMetadataMapper.updateByPrimaryKeySelective(baseMetadata);
}
}
}
return returnModel;
}
private FileMetadataWithBLOBs genOtherVersionFileMetadata(FileMetadataWithBLOBs baseMetadata, long operationTime, GitFileAttachInfo gitFileAttachInfo) {
FileMetadataWithBLOBs newMetadata = new FileMetadataWithBLOBs();
newMetadata.setDescription(baseMetadata.getDescription());
newMetadata.setId(UUID.randomUUID().toString());
newMetadata.setAttachInfo(JSONObject.toJSONString(gitFileAttachInfo));
newMetadata.setName(baseMetadata.getName());
newMetadata.setType(baseMetadata.getType());
newMetadata.setSize(baseMetadata.getSize());
newMetadata.setCreateTime(operationTime);
newMetadata.setUpdateTime(operationTime);
newMetadata.setStorage(baseMetadata.getStorage());
newMetadata.setCreateUser(SessionUtils.getUserId());
newMetadata.setProjectId(baseMetadata.getProjectId());
newMetadata.setUpdateUser(SessionUtils.getUserId());
newMetadata.setTags(baseMetadata.getTags());
newMetadata.setLoadJar(baseMetadata.getLoadJar());
newMetadata.setModuleId(baseMetadata.getModuleId());
newMetadata.setPath(baseMetadata.getPath());
newMetadata.setResourceType(baseMetadata.getResourceType());
newMetadata.setRefId(baseMetadata.getRefId());
newMetadata.setLatest(true);
return newMetadata;
}
public List<FileVersionDTO> selectFileVersion(String refId) {
List<FileVersionDTO> returnList = new ArrayList<>();
if (StringUtils.isNotBlank(refId)) {
FileMetadataExample example = new FileMetadataExample();
example.createCriteria().andRefIdEqualTo(refId);
List<FileMetadataWithBLOBs> fileMetadataList = this.fileMetadataMapper.selectByExampleWithBLOBs(example);
fileMetadataList.sort(Comparator.comparing(FileMetadataWithBLOBs::getCreateTime).reversed());
for (FileMetadataWithBLOBs fileMetadata : fileMetadataList) {
try {
if (StringUtils.isNotBlank(fileMetadata.getAttachInfo())) {
GitFileAttachInfo gitFileAttachInfo = JSONObject.parseObject(fileMetadata.getAttachInfo(), GitFileAttachInfo.class);
User user = userService.selectById(fileMetadata.getCreateUser());
FileVersionDTO dto = new FileVersionDTO(fileMetadata.getId(), gitFileAttachInfo.getCommitId(), gitFileAttachInfo.getCommitMessage(),
user == null ? fileMetadata.getCreateUser() : user.getName(), fileMetadata.getCreateTime());
returnList.add(dto);
}
} catch (Exception e) {
LogUtil.error("解析多版本下fileMetadata的attachInfo出错", e);
}
}
}
return returnList;
}
public Pager<List<FileRelevanceCaseDTO>> getFileRelevanceCase(String refId, int goPage, int pageSize) {
List<FileRelevanceCaseDTO> list = new ArrayList<>();
Page<Object> page = null;
if (StringUtils.isNotBlank(refId)) {
FileMetadataExample fileMetadataExample = new FileMetadataExample();
fileMetadataExample.createCriteria().andRefIdEqualTo(refId);
List<FileMetadataWithBLOBs> fileMetadataWithBLOBsList = fileMetadataMapper.selectByExampleWithBLOBs(fileMetadataExample);
if (CollectionUtils.isNotEmpty(fileMetadataWithBLOBsList)) {
Map<String, String> fileCommitIdMap = new HashMap<>();
fileMetadataWithBLOBsList.forEach(item -> {
if (StringUtils.isNotBlank(item.getAttachInfo()) && StringUtils.equals(item.getStorage(), StorageConstants.GIT.name())) {
try {
GitFileAttachInfo info = JSONObject.parseObject(item.getAttachInfo(), GitFileAttachInfo.class);
fileCommitIdMap.put(item.getId(), info.getCommitId());
} catch (Exception e) {
LogUtil.error("解析Git attachInfo失败", e);
}
}
});
page = PageHelper.startPage(goPage, pageSize, true);
FileAssociationExample associationExample = new FileAssociationExample();
associationExample.createCriteria().andFileMetadataIdIn(new ArrayList<>(fileCommitIdMap.keySet())).andTypeIn(new ArrayList<>() {{
this.add(FileAssociationType.API.name());
this.add(FileAssociationType.CASE.name());
this.add(FileAssociationType.SCENARIO.name());
this.add("TEST_CASE");
}});
List<FileAssociation> fileAssociationList = fileAssociationMapper.selectByExample(associationExample);
for (FileAssociation fileAssociation : fileAssociationList) {
String caseId = null;
String caseName = null;
if (StringUtils.equals(fileAssociation.getType(), FileAssociationType.API.name())) {
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(fileAssociation.getSourceId());
if (apiDefinition != null) {
caseId = apiDefinition.getNum() == null ? "" : apiDefinition.getNum().toString();
caseName = apiDefinition.getName();
}
} else if (StringUtils.equals(fileAssociation.getType(), FileAssociationType.CASE.name())) {
ApiTestCase testCase = apiTestCaseMapper.selectByPrimaryKey(fileAssociation.getSourceId());
if (testCase != null) {
caseId = testCase.getNum() == null ? "" : testCase.getNum().toString();
caseName = testCase.getName();
}
} else if (StringUtils.equals(fileAssociation.getType(), FileAssociationType.SCENARIO.name())) {
ApiScenario testCase = apiScenarioMapper.selectByPrimaryKey(fileAssociation.getSourceId());
if (testCase != null) {
caseId = testCase.getNum() == null ? "" : testCase.getNum().toString();
caseName = testCase.getName();
}
} else if (StringUtils.equals(fileAssociation.getType(), "TEST_CASE")) {
TestCase testCase = testCaseMapper.selectByPrimaryKey(fileAssociation.getSourceId());
if (testCase != null) {
caseId = testCase.getNum() == null ? "" : testCase.getNum().toString();
caseName = testCase.getName();
}
}
if (!StringUtils.isAllBlank(caseId, caseName)) {
FileRelevanceCaseDTO dto = new FileRelevanceCaseDTO(fileAssociation.getId(), caseId, caseName, fileAssociation.getType(), fileCommitIdMap.get(fileAssociation.getFileMetadataId()));
list.add(dto);
}
}
}
}
if (page == null) {
page = new Page<>(goPage, pageSize);
}
//排序一下
list.sort(Comparator.comparing(FileRelevanceCaseDTO::getCaseName));
return PageUtils.setPageInfo(page, list);
}
public String updateCaseVersion(String refId, QueryProjectFileRequest request) {
String returnString = "";
if (CollectionUtils.isNotEmpty(request.getIds())) {
FileMetadataExample example = new FileMetadataExample();
example.createCriteria().andRefIdEqualTo(refId).andLatestEqualTo(true);
List<FileMetadata> fileMetadataList = fileMetadataMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(fileMetadataList)) {
String latestId = fileMetadataList.get(0).getId();
FileAssociationExample associationExample = new FileAssociationExample();
associationExample.createCriteria().andIdIn(request.getIds());
FileAssociation fileAssociation = new FileAssociation();
fileAssociation.setFileMetadataId(latestId);
int updateCount = fileAssociationMapper.updateByExampleSelective(fileAssociation, associationExample);
returnString = String.valueOf(updateCount);
}
}
return returnString;
}
}

View File

@ -10,6 +10,7 @@ import io.metersphere.base.mapper.FileModuleMapper;
import io.metersphere.base.mapper.ext.ExtFileMetadataMapper;
import io.metersphere.base.mapper.ext.ExtFileModuleMapper;
import io.metersphere.commons.constants.ApiTestConstants;
import io.metersphere.commons.constants.FileModuleTypeConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
@ -198,6 +199,13 @@ public class FileModuleService extends NodeTreeService<FileModuleVo> {
if (fileModuleMapper.selectByExample(example).size() > 0) {
MSException.throwException(Translator.get("test_case_module_already_exists") + ": " + node.getName());
}
if (StringUtils.equalsIgnoreCase(node.getModuleType(), FileModuleTypeConstants.REPOSITORY.getValue())) {
example.clear();
criteria.andNameEqualTo(node.getName()).andProjectIdEqualTo(node.getProjectId()).andModuleTypeEqualTo(FileModuleTypeConstants.REPOSITORY.getValue());
if (fileModuleMapper.selectByExample(example).size() > 0) {
MSException.throwException(Translator.get("repository_module_already_exists") + ": " + node.getName());
}
}
}
}
@ -226,11 +234,19 @@ public class FileModuleService extends NodeTreeService<FileModuleVo> {
public int deleteNode(List<String> nodeIds) {
if (CollectionUtils.isNotEmpty(nodeIds)) {
List<String> refIdList = extFileMetadataMapper.selectRefIdsByIds(nodeIds);
//删除文件
FileMetadataExample example = new FileMetadataExample();
example.createCriteria().andModuleIdIn(nodeIds);
fileMetadataMapper.deleteByExample(example);
if (CollectionUtils.isNotEmpty(refIdList)) {
//删除其余版本的文件
example.clear();
example.createCriteria().andRefIdIn(refIdList);
fileMetadataMapper.deleteByExample(example);
}
FileModuleExample apiDefinitionNodeExample = new FileModuleExample();
apiDefinitionNodeExample.createCriteria().andIdIn(nodeIds);
return fileModuleMapper.deleteByExample(apiDefinitionNodeExample);
@ -387,5 +403,4 @@ public class FileModuleService extends NodeTreeService<FileModuleVo> {
public String getModuleNameById(String moduleId) {
return extFileModuleMapper.getNameById(moduleId);
}
}

View File

@ -0,0 +1,197 @@
package io.metersphere.metadata.utils;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.metadata.vo.repository.GitFileAttachInfo;
import io.metersphere.metadata.vo.repository.RepositoryRequest;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import java.util.*;
import java.util.stream.Collectors;
public class GitRepositoryUtils {
private final String REF_SPACE = "+refs/heads/*:refs/heads/*";
private final String DEFAULT_GIT_USERNAME = "PRIVATE-TOKEN";
private String repositoryUrl;
private String userName;
private String token;
private Git git;
public GitRepositoryUtils(String repositoryUrl, String userName, String token) {
this.repositoryUrl = StringUtils.trim(repositoryUrl);
if (StringUtils.isNotBlank(userName)) {
this.userName = StringUtils.trim(userName);
} else {
this.userName = this.DEFAULT_GIT_USERNAME;
}
this.token = StringUtils.trim(token);
LogUtil.info("初始化文件库完成. repositoryUrl" + repositoryUrl + "; userName" + userName + "; token" + token);
}
public byte[] getSingleFile(String filePath, String commitId) throws Exception {
LogUtil.info("准备获取文件. repositoryUrl" + repositoryUrl + "; filePath" + filePath + "; commitId" + commitId);
InMemoryRepository repo = this.getGitRepositoryInMemory(repositoryUrl, userName, token);
ObjectId fileCommitObjectId = repo.resolve(commitId);
RevWalk revWalk = new RevWalk(repo);
RevCommit commit = revWalk.parseCommit(fileCommitObjectId);
RevTree tree = commit.getTree();
TreeWalk treeWalk = new TreeWalk(repo);
treeWalk.addTree(tree);
treeWalk.setRecursive(true);
treeWalk.setFilter(PathFilter.create(filePath));
if (!treeWalk.next()) {
LogUtil.info("未获取到文件!. repositoryUrl" + repositoryUrl + "; filePath" + filePath + "; commitId" + commitId);
return null;
}
ObjectId objectId = treeWalk.getObjectId(0);
ObjectLoader loader = repo.open(objectId);
byte[] returnBytes = loader.getBytes();
this.closeConnection(repo);
return returnBytes;
}
public Map<String, byte[]> getFiles(List<RepositoryRequest> repositoryRequestList) throws Exception {
Map<String, byte[]> returnMap = new HashMap<>();
if (CollectionUtils.isEmpty(repositoryRequestList)) {
return returnMap;
}
Map<String, List<RepositoryRequest>> commitIdFilePathMap = repositoryRequestList.stream().collect(Collectors.groupingBy(RepositoryRequest::getCommitId));
LogUtil.info("准备批量获取文件. repositoryUrl" + repositoryUrl + "; commitIdFilePathMap" + JSONObject.toJSONString(repositoryRequestList));
InMemoryRepository repo = this.getGitRepositoryInMemory(repositoryUrl, userName, token);
ObjectId fileCommitObjectId = null;
for (Map.Entry<String, List<RepositoryRequest>> commitFilePathEntry : commitIdFilePathMap.entrySet()) {
String commitId = commitFilePathEntry.getKey();
List<RepositoryRequest> itemRequestList = commitFilePathEntry.getValue();
for (RepositoryRequest repositoryRequest : itemRequestList) {
String filePath = repositoryRequest.getFilePath();
fileCommitObjectId = repo.resolve(commitId);
RevWalk revWalk = new RevWalk(repo);
RevCommit commit = revWalk.parseCommit(fileCommitObjectId);
RevTree tree = commit.getTree();
TreeWalk treeWalk = new TreeWalk(repo);
treeWalk.addTree(tree);
treeWalk.setRecursive(true);
treeWalk.setFilter(PathFilter.create(filePath));
if (!treeWalk.next()) {
LogUtil.info("未获取到文件!. repositoryUrl" + repositoryUrl + "; filePath" + filePath + "; commitId" + commitId);
continue;
}
ObjectId objectId = treeWalk.getObjectId(0);
ObjectLoader loader = repo.open(objectId);
returnMap.put(repositoryRequest.getFileMetadataId(), loader.getBytes());
}
this.closeConnection(repo);
}
LogUtil.info("准备批量获取文件结束. repositoryUrl" + repositoryUrl);
return returnMap;
}
/**
* 获取文件的commitId
*
* @param branch
* @return 文件存在返回对应的commitid
* @throws Exception 文件不存在的时候报错
*/
public GitFileAttachInfo selectLastCommitIdByBranch(String branch, String filePath) {
GitFileAttachInfo attachInfo = null;
this.validateParams(repositoryUrl, branch, userName, token);
InMemoryRepository repo = null;
try {
repo = this.getGitRepositoryInMemory(repositoryUrl, userName, token);
ObjectId fileCommitId = repo.resolve("refs/heads/" + branch);
RevCommit commit = this.getRevTreeByRepositoryAndCommitId(repo, fileCommitId);
RevTree tree = commit.getTree();
TreeWalk treeWalk = new TreeWalk(repo);
treeWalk.addTree(tree);
treeWalk.setRecursive(true);
treeWalk.setFilter(PathFilter.create(filePath));
if (!treeWalk.next()) {
return null;
} else {
attachInfo = new GitFileAttachInfo(repositoryUrl, userName, token, branch, fileCommitId.getName(), filePath, commit.getFullMessage());
return attachInfo;
}
} catch (Exception e) {
LogUtil.error("获取文件库文件报错!", e);
} finally {
this.closeConnection(repo);
}
return null;
}
private void validateParams(String... params) {
for (String param : params) {
if (StringUtils.isBlank(param)) {
MSException.throwException("Has none params!");
}
}
}
private RevCommit getRevTreeByRepositoryAndCommitId(InMemoryRepository repo, ObjectId fileCommitId) throws Exception {
RevWalk revWalk = new RevWalk(repo);
RevCommit commit = revWalk.parseCommit(fileCommitId);
return commit;
}
private InMemoryRepository getGitRepositoryInMemory(String repositoryUrl, String userName, String token) throws Exception {
DfsRepositoryDescription repoDesc = new DfsRepositoryDescription();
InMemoryRepository repo = new InMemoryRepository(repoDesc);
CredentialsProvider credentialsProvider = new UsernamePasswordCredentialsProvider(userName, token);
git = new Git(repo);
git.fetch().setRemote(repositoryUrl).setRefSpecs(new RefSpec(REF_SPACE)).setCredentialsProvider(credentialsProvider).call();
repo.getObjectDatabase();
return repo;
}
private void closeConnection(Repository repo) {
if (git != null) {
git.close();
}
if (repo != null) {
repo.close();
}
}
public List<String> getBranches() {
List<String> returnList = new ArrayList<>();
this.validateParams(repositoryUrl, userName, token);
InMemoryRepository repo = null;
try {
Collection<Ref> refList;
UsernamePasswordCredentialsProvider pro = new UsernamePasswordCredentialsProvider(userName, token);
refList = Git.lsRemoteRepository().setRemote(repositoryUrl).setCredentialsProvider(pro).call();
refList.forEach(item -> {
returnList.add(item.getName());
});
} catch (Exception e) {
LogUtil.error("获取文件库文件报错!", e);
} finally {
this.closeConnection(repo);
}
if (CollectionUtils.isEmpty(returnList)) {
MSException.throwException("Repository connect error!");
}
return returnList;
}
}

View File

@ -12,6 +12,15 @@ public class MetadataUtils {
return "";
}
public static String getFileNameByRemotePath(String filePath) {
if (StringUtils.isBlank(filePath)) {
return "";
} else {
String[] stringArr = StringUtils.split(filePath, "/");
return stringArr[stringArr.length - 1];
}
}
public static String getFileName(String name, String type) {
type = StringUtils.isNotEmpty(type) ? type.toLowerCase() : null;
if (type != null && !name.endsWith(type)) {

View File

@ -1,6 +1,6 @@
package io.metersphere.metadata.vo;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.FileMetadataWithBLOBs;
import lombok.Data;
import java.util.List;
@ -8,5 +8,5 @@ import java.util.List;
@Data
public class DownloadRequest {
private String projectId;
private List<FileMetadata> requests;
private List<FileMetadataWithBLOBs> requests;
}

View File

@ -0,0 +1,10 @@
package io.metersphere.metadata.vo;
import io.metersphere.base.domain.FileMetadataWithBLOBs;
import lombok.Data;
@Data
public class FileMetadataCreateRequest extends FileMetadataWithBLOBs {
private String repositoryBranch;
private String repositoryPath;
}

View File

@ -8,4 +8,10 @@ import lombok.Setter;
@Setter
public class FileModuleVo extends TreeNodeDTO<FileModuleVo> {
private String path;
private String moduleType;
private String repositoryName;
private String repositoryPath;
private String repositoryUserName;
private String repositoryToken;
private String repositoryDesc;
}

View File

@ -1,6 +1,9 @@
package io.metersphere.metadata.vo;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.commons.constants.StorageConstants;
import io.metersphere.metadata.vo.repository.FileAttachInfo;
import io.metersphere.metadata.vo.repository.GitFileAttachInfo;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
@ -17,6 +20,9 @@ public class FileRequest {
private String resourceType;
private String path;
//文件附属信息
private FileAttachInfo fileAttachInfo;
public FileRequest() {
}
@ -30,4 +36,12 @@ public class FileRequest {
this.fileName = StringUtils.join(name, ".", this.type);
}
}
public void setFileAttachInfoByString(String attachInfoByString) {
if (StringUtils.isNotEmpty(attachInfoByString)) {
if (StringUtils.equals(this.storage, StorageConstants.GIT.name())) {
this.setFileAttachInfo(JSONObject.parseObject(attachInfoByString, GitFileAttachInfo.class));
}
}
}
}

View File

@ -0,0 +1,7 @@
package io.metersphere.metadata.vo.repository;
import lombok.Data;
@Data
public class FileAttachInfo {
}

View File

@ -0,0 +1,13 @@
package io.metersphere.metadata.vo.repository;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class FileInfoDTO {
private String id;
private String fileName;
private String storage;
private byte[] fileByte;
}

View File

@ -0,0 +1,14 @@
package io.metersphere.metadata.vo.repository;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class FileRelevanceCaseDTO {
public String id;
public String caseId;
public String caseName;
public String caseType;
public String commitId;
}

View File

@ -0,0 +1,14 @@
package io.metersphere.metadata.vo.repository;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class FileVersionDTO {
public String id;
public String commitId;
public String commitMessage;
public String operator;
public long operatorTime;
}

View File

@ -0,0 +1,20 @@
package io.metersphere.metadata.vo.repository;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class GitFileAttachInfo extends FileAttachInfo {
private String repositoryPath;
private String userName;
private String token;
private String branch;
private String commitId;
private String filePath;
private String commitMessage;
public String getRepositoryInfo() {
return repositoryPath + "-" + userName + "-" + token;
}
}

View File

@ -0,0 +1,10 @@
package io.metersphere.metadata.vo.repository;
import lombok.Data;
@Data
public class RepositoryRequest {
private String fileMetadataId;
private String filePath;
private String commitId;
}

View File

@ -3,6 +3,7 @@ package io.metersphere.performance.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.FileMetadataWithBLOBs;
import io.metersphere.base.domain.LoadTest;
import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.NoticeConstants;
@ -203,7 +204,7 @@ public class PerformanceTestController {
}
@PostMapping("/file/{projectId}/getMetadataByName")
public List<FileMetadata> getProjectMetadataByName(@PathVariable String projectId, @RequestBody QueryProjectFileRequest request) {
public List<FileMetadataWithBLOBs> getProjectMetadataByName(@PathVariable String projectId, @RequestBody QueryProjectFileRequest request) {
return fileMetadataService.getProjectFiles(projectId, request);
}
@ -212,7 +213,7 @@ public class PerformanceTestController {
byte[] bytes = fileMetadataService.loadFileAsBytes(fileOperationRequest.getId());
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("application/octet-stream"))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileOperationRequest.getId()+".jmx" + "\"")
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileOperationRequest.getId() + ".jmx" + "\"")
.body(bytes);
}
@ -280,7 +281,7 @@ public class PerformanceTestController {
@GetMapping("get/{version}/{refId}")
public LoadTestDTO getLoadTestByVersion(@PathVariable String version, @PathVariable String refId) {
return performanceTestService.getLoadTestByVersion(version,refId);
return performanceTestService.getLoadTestByVersion(version, refId);
}
@GetMapping("delete/{version}/{refId}")

View File

@ -2,15 +2,16 @@ package io.metersphere.service;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtFileMetadataMapper;
import io.metersphere.commons.constants.FileType;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*;
import io.metersphere.performance.request.QueryProjectFileRequest;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
@ -34,6 +35,8 @@ public class FileService {
private TestCaseFileMapper testCaseFileMapper;
@Resource
private IssueFileMapper issueFileMapper;
@Resource
private ExtFileMetadataMapper extFileMetadataMapper;
public byte[] loadFileAsBytes(String id) {
FileContent fileContent = fileContentMapper.selectByPrimaryKey(id);
@ -66,6 +69,14 @@ public class FileService {
example.createCriteria().andIdIn(ids);
fileMetadataMapper.deleteByExample(example);
List<String> refIdList = extFileMetadataMapper.selectRefIdsByIds(ids);
if (CollectionUtils.isNotEmpty(refIdList)) {
//删除其余版本的文件
example.clear();
example.createCriteria().andRefIdIn(refIdList);
fileMetadataMapper.deleteByExample(example);
}
FileContentExample example2 = new FileContentExample();
example2.createCriteria().andFileIdIn(ids);
fileContentMapper.deleteByExample(example2);
@ -93,7 +104,7 @@ public class FileService {
}
public FileMetadata saveFile(MultipartFile file, String projectId, String fileId) {
final FileMetadata fileMetadata = new FileMetadata();
final FileMetadataWithBLOBs fileMetadata = new FileMetadataWithBLOBs();
if (StringUtils.isEmpty(fileId)) {
fileMetadata.setId(UUID.randomUUID().toString());
} else {
@ -106,6 +117,8 @@ public class FileService {
fileMetadata.setUpdateTime(System.currentTimeMillis());
FileType fileType = getFileType(fileMetadata.getName());
fileMetadata.setType(fileType.name());
fileMetadata.setLatest(true);
fileMetadata.setRefId(fileMetadata.getId());
fileMetadataMapper.insert(fileMetadata);
FileContent fileContent = new FileContent();
@ -142,7 +155,7 @@ public class FileService {
if (!parentFile.exists()) {
parentFile.mkdirs();
}
try (OutputStream os = new FileOutputStream(uploadPath + "/" + attachmentName)){
try (OutputStream os = new FileOutputStream(uploadPath + "/" + attachmentName)) {
InputStream in = new ByteArrayInputStream(bytes);
int len = 0;
byte[] buf = new byte[1024];
@ -189,7 +202,7 @@ public class FileService {
}
public FileMetadata saveFile(File file, byte[] fileByte) {
final FileMetadata fileMetadata = new FileMetadata();
final FileMetadataWithBLOBs fileMetadata = new FileMetadataWithBLOBs();
fileMetadata.setId(UUID.randomUUID().toString());
fileMetadata.setName(file.getName());
fileMetadata.setSize(file.length());
@ -197,6 +210,8 @@ public class FileService {
fileMetadata.setUpdateTime(System.currentTimeMillis());
FileType fileType = getFileType(fileMetadata.getName());
fileMetadata.setType(fileType.name());
fileMetadata.setLatest(true);
fileMetadata.setRefId(fileMetadata.getId());
fileMetadataMapper.insert(fileMetadata);
FileContent fileContent = new FileContent();
@ -213,9 +228,9 @@ public class FileService {
} else {
FileMetadataExample example = new FileMetadataExample();
example.createCriteria().andProjectIdEqualTo(projectId).andNameEqualTo(file.getName());
List<FileMetadata> fileMetadatasInDataBase = fileMetadataMapper.selectByExample(example);
List<FileMetadataWithBLOBs> fileMetadatasInDataBase = fileMetadataMapper.selectByExampleWithBLOBs(example);
if (CollectionUtils.isEmpty(fileMetadatasInDataBase)) {
final FileMetadata fileMetadata = new FileMetadata();
final FileMetadataWithBLOBs fileMetadata = new FileMetadataWithBLOBs();
fileMetadata.setId(UUID.randomUUID().toString());
fileMetadata.setName(file.getName());
fileMetadata.setSize(file.length());
@ -224,6 +239,8 @@ public class FileService {
fileMetadata.setUpdateTime(System.currentTimeMillis());
FileType fileType = getFileType(fileMetadata.getName());
fileMetadata.setType(fileType.name());
fileMetadata.setLatest(true);
fileMetadata.setRefId(fileMetadata.getId());
fileMetadataMapper.insert(fileMetadata);
FileContent fileContent = new FileContent();
@ -232,7 +249,7 @@ public class FileService {
fileContentMapper.insert(fileContent);
return fileMetadata;
} else {
FileMetadata fileMetadata = fileMetadatasInDataBase.get(0);
FileMetadataWithBLOBs fileMetadata = fileMetadatasInDataBase.get(0);
fileMetadata.setName(file.getName());
fileMetadata.setSize(file.length());
fileMetadata.setProjectId(projectId);
@ -253,7 +270,7 @@ public class FileService {
}
public FileMetadata saveFile(File file, byte[] fileByte, String projectId) {
final FileMetadata fileMetadata = new FileMetadata();
final FileMetadataWithBLOBs fileMetadata = new FileMetadataWithBLOBs();
fileMetadata.setId(UUID.randomUUID().toString());
fileMetadata.setName(file.getName());
fileMetadata.setSize(file.length());
@ -262,6 +279,8 @@ public class FileService {
fileMetadata.setUpdateTime(System.currentTimeMillis());
FileType fileType = getFileType(fileMetadata.getName());
fileMetadata.setType(fileType.name());
fileMetadata.setLatest(true);
fileMetadata.setRefId(fileMetadata.getId());
fileMetadataMapper.insert(fileMetadata);
FileContent fileContent = new FileContent();
@ -273,7 +292,7 @@ public class FileService {
}
public FileMetadata saveFile(byte[] fileByte, String fileName, Long fileSize) {
final FileMetadata fileMetadata = new FileMetadata();
final FileMetadataWithBLOBs fileMetadata = new FileMetadataWithBLOBs();
fileMetadata.setId(UUID.randomUUID().toString());
fileMetadata.setName(fileName);
fileMetadata.setSize(fileSize);
@ -281,6 +300,8 @@ public class FileService {
fileMetadata.setUpdateTime(System.currentTimeMillis());
FileType fileType = getFileType(fileMetadata.getName());
fileMetadata.setType(fileType.name());
fileMetadata.setLatest(true);
fileMetadata.setRefId(fileMetadata.getId());
fileMetadataMapper.insert(fileMetadata);
FileContent fileContent = new FileContent();
@ -292,12 +313,14 @@ public class FileService {
}
public FileMetadata copyFile(String fileId) {
FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId);
FileMetadataWithBLOBs fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId);
FileContent fileContent = getFileContent(fileId);
if (fileMetadata != null && fileContent != null) {
fileMetadata.setId(UUID.randomUUID().toString());
fileMetadata.setCreateTime(System.currentTimeMillis());
fileMetadata.setUpdateTime(System.currentTimeMillis());
fileMetadata.setLatest(true);
fileMetadata.setRefId(fileMetadata.getId());
fileMetadataMapper.insert(fileMetadata);
fileContent.setFileId(fileMetadata.getId());
@ -307,7 +330,6 @@ public class FileService {
}
public FileAttachmentMetadata copyAttachment(String fileId, String attachmentType, String belongId) {
String copyPath = FileUtils.ATTACHMENT_DIR + "/" + attachmentType + "/" + belongId;
FileAttachmentMetadata fileAttachmentMetadata = fileAttachmentMetadataMapper.selectByPrimaryKey(fileId);
@ -398,7 +420,7 @@ public class FileService {
return fileMetadataMapper.selectByPrimaryKey(fileId);
}
public void updateFileMetadata(FileMetadata fileMetadata) {
public void updateFileMetadata(FileMetadataWithBLOBs fileMetadata) {
fileMetadataMapper.updateByPrimaryKeySelective(fileMetadata);
}
@ -439,13 +461,15 @@ public class FileService {
try {
RsaKey rsaKey = RsaUtil.getRsaKey();
byte[] bytes = SerializationUtils.serialize(rsaKey);
final FileMetadata fileMetadata = new FileMetadata();
final FileMetadataWithBLOBs fileMetadata = new FileMetadataWithBLOBs();
fileMetadata.setId(key);
fileMetadata.setName(key);
fileMetadata.setSize((long) bytes.length);
fileMetadata.setCreateTime(System.currentTimeMillis());
fileMetadata.setUpdateTime(System.currentTimeMillis());
fileMetadata.setType("RSA_KEY");
fileMetadata.setLatest(true);
fileMetadata.setRefId(fileMetadata.getId());
fileMetadataMapper.insert(fileMetadata);
FileContent fileContent = new FileContent();

View File

@ -63,7 +63,7 @@
</javaClientGenerator>
<!--要生成的数据库表 -->
<table tableName="api_sync_rule_relation"/>
<table tableName="file_metadata"/>
<!-- 要忽略的字段-->
<!-- <table tableName="test_case">

View File

@ -430,4 +430,6 @@ create_api_case=New interface use case
api_case_create_notice=Interface use case new notification
update_api_case=Updated interface use case
api_case_update_notice=Interface use case update notification
error_xml_struct=Data is not xml
error_xml_struct=Data is not xml
repository_module_already_exists=The repository name already exists at the same project
can_not_move_to_repository_node=Can not move to repository node

View File

@ -430,3 +430,5 @@ api_case_create_notice=接口用例新建通知
update_api_case=更新了接口用例
api_case_update_notice=接口用例更新通知
error_xml_struct=错误的xml数据
repository_module_already_exists=同项目下该文件库名称已存在
can_not_move_to_repository_node=禁止移动到文件库目录

View File

@ -429,3 +429,5 @@ api_case_create_notice=接口用例新建通知
update_api_case=更新了接口用例
api_case_update_notice=接口用例更新通知
error_xml_struct=錯誤的xml數據
repository_module_already_exists=同項目下該文件庫名稱已存在
can_not_move_to_repository_node=禁止移動到文件庫目錄

View File

@ -303,7 +303,7 @@ export default {
break;
case "scenario":
this.$router.push({
name: 'ApiAutomation',
name: 'ApiAutomationSingle',
params: {paramObj: redirectObj}
});
break;

View File

@ -47,6 +47,11 @@ export default {
name: "ApiAutomation",
component: () => import('@/business/components/api/automation/ApiAutomation'),
},
{
path: "automation",
name: "ApiAutomationSingle",
component: () => import('@/business/components/api/automation/ApiAutomation'),
},
{
path: 'monitor/view',
name: 'ApiMonitor',

View File

@ -4,7 +4,8 @@
<ms-file-module @nodeSelectEvent="change" @myFile="myFile" @setNodeTree="setNodeTree" ref="module"/>
</ms-aside-container>
<ms-main-container>
<resource-manage ref="resourceManage" :moduleId="moduleId" :nodeTree="nodeTree" @refreshModule="refreshModule"/>
<resource-manage ref="resourceManage" :moduleId="moduleId" :module-type="moduleType" :nodeTree="nodeTree"
@refreshModule="refreshModule"/>
</ms-main-container>
</ms-container>
</template>
@ -31,12 +32,14 @@ export default {
data() {
return {
moduleId: "",
moduleType: "module",
nodeTree: []
}
},
methods: {
change(node, nodeIds, pNodes) {
this.moduleId = node.data.id;
this.moduleType = node.data.moduleType;
this.$refs.resourceManage.moduleChange(nodeIds);
},
myFile() {
@ -45,7 +48,7 @@ export default {
setNodeTree(data) {
this.nodeTree = data;
},
refreshModule(){
refreshModule() {
this.$refs.module.refresh();
}
}

View File

@ -0,0 +1,149 @@
<template>
<el-dialog :title="dialogTitle"
:visible.sync="dialogFormVisible"
:before-close="close"
width="600px">
<el-form :model="metadataForm" :rules="metadataRule" ref="form" label-width="80px" @submit.native.prevent>
<el-form-item
:label="$t('project.project_file.file.branch')"
prop="repositoryBranch">
<el-input v-model="metadataForm.repositoryBranch"></el-input>
</el-form-item>
<el-form-item
:label="$t('project.project_file.file.path')"
prop="repositoryPath">
<el-input v-model="metadataForm.repositoryPath"></el-input>
</el-form-item>
</el-form>
<template v-slot:footer>
<el-button @click="close">{{ $t('commons.cancel') }}</el-button>
<el-button v-xpack v-prevent-re-click type="primary" :loading="isSaveBtnLoading" @click="saveFileMetadata"
@keydown.enter.native.prevent>{{ $t('commons.confirm') }}
</el-button>
</template>
</el-dialog>
</template>
<script>
import {getCurrentProjectID, getCurrentUserId, getUUID, listenGoBack, removeGoBackListener} from "@/common/js/utils";
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
export default {
name: "FileMetadataDialog",
components: {
MsDialogFooter,
},
data() {
return {
dialogFormVisible: false,
dialogTitle: '',
operationType: '',
isSaveBtnLoading: false,
projectId: getCurrentProjectID(),
metadataForm: {
repositoryBranch: '',
repositoryPath: '',
},
metadataRule: {
repositoryBranch: [
{required: true, message: this.$t('project.project_file.validation.input_file_branch'), trigger: 'blur'},
],
repositoryPath: [
{required: true, message: this.$t('project.project_file.validation.input_file_path'), trigger: 'blur'},
],
},
}
},
watch: {},
props: {
moduleId: String,
},
computed: {},
methods: {
saveFileMetadata() {
this.$refs.form.validate(valid => {
if (valid) {
let url = '';
let param = JSON.parse(JSON.stringify(this.metadataForm));
param.storage = 'GIT';
if (param.id) {
url = "/file/metadata/edit";
} else {
url = "/file/metadata/create";
param.id = getUUID();
param.createUser = getCurrentUserId();
param.updateUser = getCurrentUserId();
param.projectId = this.projectId;
param.moduleId = this.moduleId;
}
let formData = new FormData();
formData.append("request", new Blob([JSON.stringify(param)], {type: "application/json"}));
let options = {
method: 'POST',
url: url,
data: formData,
headers: {
'Content-Type': undefined
}
};
this.isSaveBtnLoading = true;
this.result = this.$request(options, () => {
this.$success(this.$t('commons.save_success'));
this.$emit('refresh');
this.isSaveBtnLoading = false;
this.close();
}, (error) => {
this.$emit('refresh');
this.isSaveBtnLoading = false;
});
} else {
return false;
}
});
},
open(operationType, param) {
this.isSaveBtnLoading = false;
listenGoBack(this.close);
this.initDialog(operationType);
if (param) {
this.metadataForm = JSON.parse(JSON.stringify(param));
} else {
this.metadataForm = {
repositoryBranch: '',
repositoryPath: '',
};
}
this.dialogFormVisible = true;
},
close() {
this.isSaveBtnLoading = false;
removeGoBackListener(this.close);
this.$refs.form.resetFields();
this.dialogFormVisible = false;
},
initDialog(operationType) {
this.operationType = operationType;
//-title
if (operationType === 'create') {
this.dialogTitle = this.$t('commons.create');
} else if (operationType === 'edit') {
this.dialogTitle = this.$t('commons.edit');
} else {
this.dialogTitle = '';
}
},
clearForm() {
this.metadataForm = {
repositoryBranch: '',
repositoryPath: '',
};
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,235 @@
<template>
<el-dialog :title="dialogTitle"
:visible.sync="dialogFormVisible"
:before-close="close"
width="600px">
<el-row v-show="operationType==='create'" type="flex" justify="center" style="margin-bottom: 10px;">
<el-radio-group v-model="moduleForm.moduleType">
<el-radio label="module">{{ $t("project.project_file.file_module_type.module") }}</el-radio>
<el-radio v-xpack label="repository">{{ $t("project.project_file.file_module_type.repository") }}</el-radio>
</el-radio-group>
</el-row>
<el-form :model="moduleForm" :rules="moduleRule" ref="form" label-width="100px" @submit.native.prevent>
<el-form-item v-show="moduleForm.moduleType === 'module'"
:label="$t('test_track.module.name')"
prop="name">
<el-input v-model="moduleForm.name"></el-input>
</el-form-item>
<div v-show="moduleForm.moduleType === 'repository'">
<el-form-item
:label="$t('project.project_file.repository.name')"
prop="name">
<el-input v-model="moduleForm.name"></el-input>
</el-form-item>
<el-form-item
:label="$t('project.project_file.repository.path')"
prop="repositoryPath">
<el-input v-model="moduleForm.repositoryPath"></el-input>
</el-form-item>
<el-form-item
:label="$t('api_test.request.tcp.username')"
prop="repositoryUserName">
<el-input v-model="moduleForm.repositoryUserName">
<template slot="append">
<el-tooltip class="item" effect="dark"
:content="$t('project.project_file.validation.input_gitee_user_please')" placement="top">
<i class="el-icon-info"/>
</el-tooltip>
</template>
</el-input>
</el-form-item>
<el-form-item
:label="$t('project.project_file.repository.token')"
prop="repositoryToken">
<el-input v-model="moduleForm.repositoryToken"></el-input>
</el-form-item>
<el-form-item
type="textarea"
:label="$t('project.project_file.repository.desc')"
prop="repositoryDesc">
<el-input v-model="moduleForm.repositoryDesc"></el-input>
</el-form-item>
</div>
</el-form>
<template v-slot:footer>
<div class="dialog-footer">
<el-button @click="close">{{ $t('commons.cancel') }}</el-button>
<el-button v-prevent-re-click :loading="isConnBtnLoading" type="primary" @click="testConnect"
v-show="moduleForm.moduleType === 'repository'"
@keydown.enter.native.prevent>
{{ $t('system_parameter_setting.test_connection') }}
</el-button>
<el-button v-prevent-re-click :loading="isSaveBtnLoading" type="primary" @click="saveFileModule"
@keydown.enter.native.prevent>
{{ $t('commons.confirm') }}
</el-button>
</div>
</template>
</el-dialog>
</template>
<script>
import {getCurrentProjectID, listenGoBack, removeGoBackListener} from "@/common/js/utils";
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
export default {
name: "FileModuleDialog",
components: {
MsDialogFooter,
},
data() {
return {
dialogFormVisible: false,
dialogTitle: '',
operationType: '',
projectId: getCurrentProjectID(),
isConnBtnLoading: false,
isSaveBtnLoading: false,
moduleForm: {
name: '',
moduleType: 'module',
repositoryUserName: '',
repositoryPath: '',
repositoryToken: '',
repositoryDesc: '',
},
moduleRule: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 60, message: this.$t('test_track.length_less_than') + '60', trigger: 'blur'}
],
},
}
},
watch: {
'moduleForm.moduleType'() {
if (this.moduleForm.moduleType === 'module') {
this.moduleRule = {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 60, message: this.$t('test_track.length_less_than') + '60', trigger: 'blur'}
],
};
} else if (this.moduleForm.moduleType === 'repository') {
this.moduleRule = {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 60, message: this.$t('test_track.length_less_than') + '60', trigger: 'blur'}
],
repositoryPath: [
{
required: true,
message: this.$t('project.project_file.validation.input_repository_path'),
trigger: 'blur'
},
{max: 255, message: this.$t('test_track.length_less_than') + '255', trigger: 'blur'},
{
pattern: '(.*)\.git$',
message: this.$t('project.project_file.validation.input_repository_path'),
trigger: 'blur'
}
],
repositoryToken: [
{
required: true,
message: this.$t('project.project_file.validation.input_repository_token'),
trigger: 'blur'
},
{max: 255, message: this.$t('test_track.length_less_than') + '255', trigger: 'blur'}
],
};
}
}
},
props: {},
computed: {},
methods: {
testConnect() {
let param = this.moduleForm;
let url = "/file/module/connect";
this.isConnBtnLoading = true;
this.$post(url, param, () => {
this.$success(this.$t('commons.connection_successful'));
this.isConnBtnLoading = false;
}, (error) => {
this.$emit('refresh');
this.isConnBtnLoading = false;
});
},
saveFileModule() {
this.$refs.form.validate(valid => {
if (valid) {
let url = '';
if (this.operationType === 'create') {
url = "/file/module/add";
} else if (this.operationType === 'edit') {
url = "/file/module/edit";
}
let param = this.moduleForm;
param.projectId = this.projectId;
this.isSaveBtnLoading = true;
this.$post(url, param, () => {
this.$success(this.$t('commons.save_success'));
this.$emit('refresh');
this.isSaveBtnLoading = false;
this.close();
}, (error) => {
this.isSaveBtnLoading = false;
this.$emit('refresh');
});
} else {
return false;
}
});
},
open(operationType, param) {
this.isSaveBtnLoading = false;
this.isConnBtnLoading = false;
listenGoBack(this.close);
this.initDialog(operationType);
if (operationType === 'create') {
param.moduleType = 'module';
}
this.moduleForm = JSON.parse(JSON.stringify(param));
this.dialogFormVisible = true;
},
close() {
this.isSaveBtnLoading = false;
this.isConnBtnLoading = false;
removeGoBackListener(this.close);
this.$refs.form.resetFields();
this.dialogFormVisible = false;
},
initDialog(operationType) {
this.operationType = operationType;
//-title
if (operationType === 'create') {
this.dialogTitle = this.$t('commons.create');
} else if (operationType === 'edit') {
this.dialogTitle = this.$t('commons.edit');
} else {
this.dialogTitle = '';
}
},
clearForm() {
this.moduleForm = {
name: '',
moduleType: 'module',
repositoryPath: '',
repositoryToken: '',
repositoryUserName: '',
repositoryDesc: '',
};
}
}
}
</script>
<style scoped>
</style>

View File

@ -5,106 +5,132 @@
<span>{{ data.name }}</span>
<i class="el-icon-download ms-header-menu" @click="download" v-permission="['PROJECT_FILE:READ+DOWNLOAD+JAR']"/>
<i class="el-icon-delete ms-header-menu" @click="deleteData" v-permission="['PROJECT_FILE:READ+DELETE+JAR']"/>
<el-button v-if="isRepositoryFile()" :loading="isPullBtnLoading" class="ms-header-menu" size="mini"
@click="filePull"
style="padding: 2px;font-size: 12px">pull</el-button>
</span>
<el-row align="center" v-loading="loading">
<el-col style="margin: 10px" :span="10">
<el-row :gutter="20" style="background: #F5F6F8;height: 480px">
<el-col :span="2" class="ms-left-col">
<i class="el-icon-arrow-left ms-icon-arrow" @click="beforeData"/>
<el-tabs v-if="visible" tab-position="right" v-model="showPanel"
:class=" isRepositoryFile()?'':'file-metadata-tab'">
<el-tab-pane name="baseInfo" :label=" isRepositoryFile()?$t('test_track.plan_view.base_info'):''">
<el-row align="center" v-loading="loading">
<el-col style="margin: 10px" :span="10">
<el-row :gutter="20" style="background: #F5F6F8;height: 480px">
<el-col :span="2" class="ms-left-col">
<i class="el-icon-arrow-left ms-icon-arrow" @click="beforeData"/>
</el-col>
<el-col :span="18" style="padding-top: 80px">
<el-card :body-style="{ padding: '0px' }" v-if="isImage(data.type) && !isRepositoryFile()">
<img :src="'/file/metadata/info/' + data.id" class="ms-edit-image"/>
</el-card>
<el-card :body-style="{ padding: '0px' }" v-else>
<div class="ms-edit-image">
<div class="ms-file-item">
<div class="icon-title">{{ getType(data.type) }}</div>
</div>
</div>
</el-card>
</el-col>
<el-col :span="2" class="ms-right-col">
<i class="el-icon-arrow-right ms-icon-arrow" @click="nextData"/>
</el-col>
</el-row>
</el-col>
<el-col :span="18" style="padding-top: 80px">
<el-card :body-style="{ padding: '0px' }" v-if="isImage(data.type)">
<img :src="'/file/metadata/info/' + data.id" class="ms-edit-image"/>
</el-card>
<el-card :body-style="{ padding: '0px' }" v-else>
<div class="ms-edit-image">
<div class="ms-file-item">
<div class="icon-title">{{ getType(data.type) }}</div>
</div>
</div>
</el-card>
</el-col>
<el-col :span="2" class="ms-right-col">
<i class="el-icon-arrow-right ms-icon-arrow" @click="nextData"/>
<el-col :span="13">
<el-container>
<el-main>
<el-form :model="data" :rules="rules" label-position="right" label-width="80px" size="small" ref="form">
<!-- 基础信息 -->
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="data.description"
type="textarea"
:rows="2" size="small" @blur="save"/>
</el-form-item>
<el-form-item :label="$t('load_test.file_name')" prop="name">
<el-input
class="ms-file-item-input"
size="small"
v-model="data.name"
:disabled="isRepositoryFile()"
show-word-limit @blur="save"/>
</el-form-item>
<el-form-item :label="$t('load_test.file_type')" prop="type">
<span>{{ data.type }}</span>
</el-form-item>
<el-form-item v-if="!isRepositoryFile()" :label="$t('load_test.file_size')" prop="size">
<span>{{ formatFileSize(data.size) }}</span>
</el-form-item>
<el-form-item :label="$t('api_test.automation.tag')" prop="tags">
<ms-input-tag :currentScenario="data" ref="tag" @onblur="save"/>
</el-form-item>
<el-form-item :label="$t('test_track.case.module')" prop="moduleId">
<ms-select-tree :disabled="isRepositoryFile()" size="small" :data="moduleOptions"
:defaultKey="data.moduleId"
@getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
</el-form-item>
<el-form-item :label="$t('project.creator')" prop="createUser">
<span>{{ data.createUser }}</span>
</el-form-item>
<el-form-item :label="$t('commons.create_time')" prop="createTime">
<span>{{ data.createTime | timestampFormatDate }}</span>
</el-form-item>
<el-form-item :label="'加载Jar包'" prop="loadJar" v-if="data.type === 'JAR'">
<el-switch v-model="data.loadJar" :active-text="$t('project.file_jar_message')" @change="save"/>
</el-form-item>
<el-form-item v-if="isRepositoryFile()" :label="$t('commons.version')">
{{ getCommitId() }}
</el-form-item>
<el-form-item v-else :label="$t('project.upload_file_again')" prop="files">
<el-upload
style="width: 38px; float: left;"
action="#"
:before-upload="beforeUploadFile"
:http-request="handleUpload"
:show-file-list="false"
v-permission="['PROJECT_FILE:READ+UPLOAD+JAR']">
<el-button icon="el-icon-plus" size="mini"/>
</el-upload>
</el-form-item>
</el-form>
</el-main>
</el-container>
</el-col>
</el-row>
</el-col>
<el-col :span="13">
<el-form :model="data" :rules="rules" label-position="right" label-width="80px" size="small" ref="form">
<!-- 基础信息 -->
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="data.description"
type="textarea"
:rows="2" size="small" @blur="save"/>
</el-form-item>
<el-form-item :label="$t('load_test.file_name')" prop="name">
<el-input
class="ms-file-item-input"
size="small"
v-model="data.name"
show-word-limit @blur="save"/>
</el-form-item>
<el-form-item :label="$t('load_test.file_type')" prop="type">
<span>{{ data.type }}</span>
</el-form-item>
<el-form-item :label="$t('load_test.file_size')" prop="size">
<span>{{ formatFileSize(data.size) }}</span>
</el-form-item>
<el-form-item :label="$t('api_test.automation.tag')" prop="tags">
<ms-input-tag :currentScenario="data" ref="tag" @onblur="save"/>
</el-form-item>
<el-form-item :label="$t('test_track.case.module')" prop="moduleId">
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="data.moduleId"
@getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
</el-form-item>
<el-form-item :label="$t('project.creator')" prop="createUser">
<span>{{ data.createUser }}</span>
</el-form-item>
<el-form-item :label="$t('commons.create_time')" prop="createTime">
<span>{{ data.createTime | timestampFormatDate }}</span>
</el-form-item>
<el-form-item :label="'加载Jar包'" prop="loadJar" v-if="data.type === 'JAR'">
<el-switch v-model="data.loadJar" :active-text="$t('project.file_jar_message')" @change="save"/>
</el-form-item>
<el-form-item :label="$t('project.upload_file_again')" prop="files">
<el-upload
style="width: 38px; float: left;"
action="#"
:before-upload="beforeUploadFile"
:http-request="handleUpload"
:show-file-list="false"
v-permission="['PROJECT_FILE:READ+UPLOAD+JAR']">
<el-button icon="el-icon-plus" size="mini"/>
</el-upload>
</el-form-item>
</el-form>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane name="relevanceCase" v-if="isRepositoryFile()"
:label=" $t('test_track.review_view.relevance_case')">
<file-case-relevance-list :file-metadata-ref-id="data.refId"/>
</el-tab-pane>
<el-tab-pane name="versionHistory" v-if="isRepositoryFile()"
:label=" $t('project.project_file.repository.version_history')">
<file-version-list :file-metadata-ref-id="data.refId"/>
</el-tab-pane>
</el-tabs>
</el-dialog>
</template>
<script>
import {getCurrentProjectID, operationConfirm} from "@/common/js/utils";
import {hasPermission} from "../../../../../../common/js/utils";
import FileCaseRelevanceList from "@/business/components/project/menu/file/list/FileCaseRelevanceList";
import FileVersionList from "@/business/components/project/menu/file/list/FileVersionList";
export default {
name: "MsEditFileMetadata",
components: {
MsSelectTree: () => import("../../../../common/select-tree/SelectTree"),
MsInputTag: () => import("../../../../api/automation/scenario/MsInputTag"),
FileCaseRelevanceList,
FileVersionList,
},
data() {
return {
@ -112,6 +138,8 @@ export default {
visible: false,
isFirst: false,
isLast: false,
isPullBtnLoading: false,
showPanel: "baseInfo",
results: [],
moduleObj: {
id: 'id',
@ -148,6 +176,36 @@ export default {
},
},
methods: {
getCommitId() {
if (this.data && this.data.attachInfo) {
return JSON.parse(this.data.attachInfo).commitId;
} else {
return "";
}
},
filePull() {
this.isPullBtnLoading = true;
let formData = new FormData();
formData.append("request", new Blob([JSON.stringify({id: this.data.id})], {type: "application/json"}));
let options = {
method: 'POST',
url: '/file/metadata/git/pull',
data: formData,
headers: {
'Content-Type': undefined
}
};
this.result = this.$request(options, () => {
this.$success(this.$t('commons.update') + this.$t('api_test.automation.request_success'));
this.isPullBtnLoading = false;
this.$emit("reload");
this.close();
}, (error) => {
this.isPullBtnLoading = false;
});
},
beforeUploadFile(file) {
if (!this.fileValidator(file)) {
return false;
@ -169,13 +227,16 @@ export default {
}
},
close() {
this.showPanel = "baseInfo";
this.visible = false;
},
saveAndClose() {
this.showPanel = "baseInfo";
this.visible = false;
this.$emit("setCurrentPage", this.currentPage);
},
open(data, size, page, t) {
this.showPanel = "baseInfo";
this.pageSize = size;
this.currentPage = page;
this.total = t;
@ -183,6 +244,9 @@ export default {
this.results = this.metadataArray;
this.visible = true;
},
isRepositoryFile() {
return this.data.storage === 'GIT';
},
save() {
this.$refs['form'].validate((valid) => {
if (valid) {
@ -200,7 +264,11 @@ export default {
});
},
getType(type) {
return type || "";
if (this.isRepositoryFile()) {
return "Repository " + type || "";
} else {
return type || "";
}
},
isImage(type) {
return (type && this.images.indexOf(type.toLowerCase()) !== -1);
@ -261,6 +329,7 @@ export default {
});
},
beforeData() {
this.showPanel = "baseInfo";
const index = this.results.findIndex(e => e.id === this.data.id);
this.isFirst = index <= 0;
if (!this.isFirst) {
@ -292,6 +361,7 @@ export default {
return val + " " + list[num];
},
nextData() {
this.showPanel = "baseInfo";
const index = this.results.findIndex(e => e.id === this.data.id);
this.isLast = (this.results.length - 1) === index;
if (!this.isLast) {
@ -369,4 +439,8 @@ export default {
cursor: pointer;
color: var(--color);
}
.file-metadata-tab >>> .el-tabs__active-bar {
background-color: white;
}
</style>

View File

@ -0,0 +1,141 @@
<template>
<div>
<ms-table
class="basic-config"
:batch-operators="buttons"
:data="tableData"
:condition="condition"
:hidePopover="true"
:total="total"
enableSelection
showSelectAll
@refresh="selectData" ref="table">
<ms-table-column
label="ID"
:min-width="120"
prop="caseId">
</ms-table-column>
<ms-table-column
:label="$t('api_test.home_page.failed_case_list.table_coloum.case_name')"
:min-width="120"
prop="caseName">
</ms-table-column>
<ms-table-column
:label="$t('project.project_file.repository.file_version')"
:min-width="120"
prop="caseType">
<template v-slot="scope">
<span v-if="scope.row.caseType === 'API'">
{{ $t('api_test.home_page.api_details_card.title') }}
</span>
<span v-else-if="scope.row.caseType === 'CASE'">
{{ $t('commons.api_case') }}
</span>
<span v-else-if="scope.row.caseType === 'SCENARIO'">
{{ $t('commons.scenario_case') }}
</span>
<span v-else-if="scope.row.caseType === 'TEST_CASE'">
{{ $t('commons.test_case') }}
</span>
</template>
</ms-table-column>
<ms-table-column
:label="$t('project.project_file.repository.file_version')"
:min-width="120"
prop="commitId">
</ms-table-column>
<el-table-column :label="$t('commons.operating')" fixed="right" :width="130">
<template v-slot:default="scope">
<el-button size="mini" @click="updateFileVersion(scope.row)" style="padding: 4px;font-size: 12px">PULL
</el-button>
</template>
</el-table-column>
</ms-table>
<table-pagination
:change="selectData"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:total="total"/>
</div>
</template>
<script>
import MsTable from "@/business/components/common/components/table/MsTable";
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
import MsTableOperatorButton from "@/business/components/common/components/MsTableOperatorButton";
import TablePagination from "@/business/components/common/pagination/TablePagination";
import MsTableHeaderSelectPopover from "@/business/components/common/components/table/MsTableHeaderSelectPopover";
export default {
name: "FileCaseRelevanceList",
components: {
MsTable, MsTableColumn, MsTableOperatorButton, TablePagination, MsTableHeaderSelectPopover
},
data() {
return {
tableData: [],
selectNodeIds: [],
currentPage: 1,
pageSize: 10,
total: 0,
metadataArr: [],
fileNumLimit: 10,
condition: {},
buttons: [
{
name: 'PULL',
handleClick: this.batchUpdateFileVersion
},
],
};
},
props: {
fileMetadataRefId: String,
},
watch: {
fileMetadataRefId() {
this.selectData();
}
},
created() {
this.selectData();
},
methods: {
selectData() {
this.$post('/file/metadata/file/relevance/case/' + this.fileMetadataRefId + "/" + this.currentPage + "/" + this.pageSize, this.condition, res => {
let returnData = res.data;
this.total = returnData.itemCount;
this.tableData = returnData.listObject;
});
},
updateFileVersion(row) {
this.condition.ids = [row.id];
this.$post('/file/metadata/case/version/update/' + this.fileMetadataRefId, this.condition, res => {
this.$success('Pull ' + this.$t('variables.end'));
this.selectData();
});
},
batchUpdateFileVersion() {
let selectIds = this.$refs.table.selectIds;
this.condition.ids = selectIds;
this.$post('/file/metadata/case/version/update/' + this.fileMetadataRefId, this.condition, res => {
this.$success('Pull ' + this.$t('variables.end'));
this.selectData();
});
},
},
}
</script>
<style scoped>
</style>

View File

@ -7,6 +7,7 @@
@search="getProjectFiles" title="">
<template v-slot:button>
<el-upload
v-if="moduleType==='module'"
action=""
:limit="fileNumLimit"
multiple
@ -15,9 +16,13 @@
:http-request="handleUpload"
:on-exceed="handleExceed">
<ms-table-button icon="el-icon-upload2"
:content="$t('load_test.upload_file')"
:content="$t('variables.add_file')"
v-permission="['PROJECT_FILE:READ+UPLOAD+JAR']"/>
</el-upload>
<ms-table-button icon="el-icon-upload2" v-else-if="moduleType==='repository'"
:content="$t('variables.add_file')"
@click="addRepositoryFile"
v-permission="['PROJECT_FILE:READ+UPLOAD+JAR']"/>
</template>
</ms-table-header>
</template>
@ -162,6 +167,7 @@
@download="handleDownload"
@setCurrentPage="setCurrentPage"
@delete="handleDelete" ref="editFileMetadata"/>
<file-metadata-dialog :module-id="moduleId" @refresh="refreshModuleAndList" ref="repositoryFileDialog"/>
</el-card>
</template>
@ -169,7 +175,7 @@
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import MsTableButton from "@/business/components/common/components/MsTableButton";
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
import {getCurrentProjectID, operationConfirm, getCurrentUserId} from "@/common/js/utils";
import {getCurrentProjectID, getCurrentUserId, operationConfirm} from "@/common/js/utils";
import MsTableOperatorButton from "@/business/components/common/components/MsTableOperatorButton";
import MsTableHeader from "../header/FileHeader";
import MsTableSearchBar from "@/business/components/common/components/MsTableSearchBar";
@ -181,6 +187,7 @@ import MsFileBatchMove from "../module/FileBatchMove";
import MsFileThumbnail from "./FileThumbnail";
import MsEditFileMetadata from "../edit/EditFileMetadata";
import MsTag from "@/business/components/common/components/MsTag";
import FileMetadataDialog from "@/business/components/project/menu/file/dialog/FileMetadataDialog";
export default {
name: "MsFileMetadataList",
@ -198,10 +205,15 @@ export default {
MsFileBatchMove,
MsFileThumbnail,
MsEditFileMetadata,
MsTag
MsTag,
FileMetadataDialog,
},
props: {
moduleId: String,
moduleType: {
type: String,
default: 'module',
},
nodeTree: Array,
},
data() {
@ -287,6 +299,10 @@ export default {
});
});
},
refreshModuleAndList() {
this.getProjectFiles();
this.refreshModule();
},
fileValidator(file) {
/// todo:
return file.size > 0;
@ -306,7 +322,12 @@ export default {
let file = uploadResources.file;
let formData = new FormData();
let url = '/file/metadata/create';
let request = {createUser: getCurrentUserId(), updateUser: getCurrentUserId(), projectId: this.projectId, moduleId: this.moduleId};
let request = {
createUser: getCurrentUserId(),
updateUser: getCurrentUserId(),
projectId: this.projectId,
moduleId: this.moduleId,
};
formData.append("request", new Blob([JSON.stringify(request)], {type: "application/json"}));
formData.append("file", file);
let options = {
@ -414,6 +435,9 @@ export default {
},
moveSave(param) {
this.buildBatchParam(param);
},
addRepositoryFile() {
this.$refs.repositoryFileDialog.open("create");
}
}
};

View File

@ -0,0 +1,63 @@
<template>
<div>
<el-table :data="data" class="test-content document-table" style="width: 100%" ref="table">
<el-table-column prop="commitId"
:label="$t('project.project_file.repository.file_version')"
min-width="120px"
show-overflow-tooltip/>
<el-table-column prop="commitMessage"
:label="$t('project.project_file.repository.update_log')"
min-width="200"
show-overflow-tooltip/>
<el-table-column prop="operator"
:label="$t('operating_log.user')"
min-width="120"
show-overflow-tooltip/>
<el-table-column prop="operatorTime" min-width="160" :label="$t('operating_log.time')" sortable>
<template v-slot:default="scope">
<span>{{ scope.row.operatorTime | timestampFormatDate }}</span>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: "FileVersionList",
data() {
return {
data: [],
};
},
props: {
fileMetadataRefId: String,
},
watch: {
fileMetadataRefId() {
this.selectData();
}
},
created() {
this.selectData();
},
methods: {
selectData() {
if (this.fileMetadataRefId) {
this.$get('file/metadata/fileVersion/' + this.fileMetadataRefId, response => {
if (response.data) {
this.data = response.data;
}
this.$nextTick(() => {
this.$refs.table.doLayout();
})
});
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -5,6 +5,11 @@
:destroy-on-close="true" width="600px"
v-loading="loading" append-to-body class="batch-move">
<div>
<div v-xpack style="margin-bottom: 5px">
<i class="el-icon-info"/>
<span>{{ $t('project.project_file.validation.can_not_move_repository_file') }}</span>
</div>
<el-input :placeholder="$t('test_track.module.search')" v-model="filterText" size="small"/>
<el-tree
class="filter-tree node-tree"
@ -90,7 +95,7 @@ export default {
});
},
save() {
if (!this.currentKey || this.currentKey ==='') {
if (!this.currentKey || this.currentKey === '') {
this.$warning(this.$t('test_track.case.input_module'));
return;
}

View File

@ -11,13 +11,16 @@
:update-permission="['PROJECT_API_SCENARIO:READ+EDIT']"
:default-label="$t('commons.module_title')"
:show-case-num="showCaseNum"
@add="add"
operation_type_add="external"
operation_type_edit="external"
@edit="edit"
@drag="drag"
@remove="remove"
@refresh="list"
@filter="filter"
@nodeSelectEvent="nodeChange"
@addOperation="fileTreeModuleAdd"
@editOperation="fileTreeModuleEdit"
ref="nodeTree">
<template v-slot:header>
@ -26,8 +29,8 @@
:condition="condition"/>
<ms-my-file :condition="condition" :exe="myFile" :total='total' v-if="loading"/>
</template>
</ms-node-tree>
<file-module-dialog @refresh="list" ref="fileModuleDialog"/>
</div>
</template>
@ -37,6 +40,7 @@ import {buildTree} from "@/business/components/api/definition/model/NodeTree";
import MsMyFile from "./MyFile";
import MsSearchBar from "@/business/components/common/components/search/MsSearchBar";
import {getCurrentProjectID, getCurrentUserId} from "@/common/js/utils";
import FileModuleDialog from "@/business/components/project/menu/file/dialog/FileModuleDialog";
export default {
name: 'MsFileModule',
@ -44,6 +48,7 @@ export default {
MsSearchBar,
MsMyFile,
MsNodeTree,
FileModuleDialog,
},
props: {
isReadOnly: {
@ -95,6 +100,12 @@ export default {
}
},
methods: {
fileTreeModuleAdd(param) {
this.$refs.fileModuleDialog.open('create', param);
},
fileTreeModuleEdit(data) {
this.$refs.fileModuleDialog.open('edit', data);
},
reload() {
this.loading = false
this.$nextTick(() => {
@ -138,16 +149,6 @@ export default {
this.list();
});
},
add(param) {
param.projectId = this.projectId;
param.protocol = this.condition.protocol;
this.$post("/file/module/add", param, () => {
this.$success(this.$t('commons.save_success'));
this.list();
}, (error) => {
this.list();
});
},
remove(nodeIds) {
this.$post("/file/module/delete", nodeIds, () => {
this.list();

View File

@ -117,6 +117,16 @@ export default {
type: String,
default: "view"
},
//
operation_type_add: {
type: String,
default: "simple"
},
//
operation_type_edit: {
type: String,
default: "simple"
},
treeNodes: {
type: Array
},
@ -254,20 +264,23 @@ export default {
}
},
edit(node, data, isAppend) {
this.$set(data, 'isEdit', true);
this.$nextTick(() => {
this.$refs.nameInput.focus();
// this.$set(data, 'isEdit', true);
if (!isAppend) {
this.$nextTick(() => {
this.filter(this.filterText);
});
this.$nextTick(() => {
this.$emit('filter');
});
}
});
if (this.operation_type_edit === 'simple') {
this.$set(data, 'isEdit', true);
this.$nextTick(() => {
this.$refs.nameInput.focus();
// this.$set(data, 'isEdit', true);
if (!isAppend) {
this.$nextTick(() => {
this.filter(this.filterText);
});
this.$nextTick(() => {
this.$emit('filter');
});
}
});
} else if (this.operation_type_edit === 'external') {
this.$emit("editOperation", data);
}
},
increase(id) {
this.traverse(id, node => {
@ -317,21 +330,33 @@ export default {
}
},
append(node, data) {
const newChild = {
id: undefined,
isEdit: false,
name: "",
children: []
};
if (!data.children) {
this.$set(data, 'children', [])
if (this.operation_type_add === 'simple') {
const newChild = {
id: undefined,
isEdit: false,
name: "",
children: []
};
if (!data.children) {
this.$set(data, 'children', [])
}
data.children.push(newChild);
this.edit(node, newChild, true);
node.expanded = true;
this.$nextTick(() => {
this.$refs.nameInput.focus();
});
} else if (this.operation_type_add === 'external') {
let param = {};
param.parentId = node.id;
param.level = 1;
if (data.id != 'root') {
//
param.parentId = data.id;
param.level = data.level + 1;
}
this.$emit("addOperation", param);
}
data.children.push(newChild);
this.edit(node, newChild, true);
node.expanded = true;
this.$nextTick(() => {
this.$refs.nameInput.focus();
});
},
save(node, data) {
if (data.name.trim() === '') {

View File

@ -870,6 +870,34 @@ export default {
compare: 'Compare',
change_latest_tip: 'This operation will modify the default display of the interface, scene, test case and other list pages, which may take some time. Please wait! '
},
project_file: {
file_module_type: {
module: 'Module',
repository: 'Repository'
},
file: {
branch: 'File branck',
path: 'File path',
},
repository: {
name: 'Repository name',
path: 'Path',
token: 'Token',
desc: 'Description',
version_history: 'History',
file_version: 'Version',
update_log: 'Commit log',
},
validation: {
input_repository_name: 'Input repository name',
input_repository_path: 'Input repository path',
input_repository_token: 'Input repository token',
input_file_branch: 'Input file branch',
input_file_path: 'Input file path',
input_gitee_user_please: 'Gitee uses need input user name',
can_not_move_repository_file: 'Repository file can not move',
},
},
timing_clean_plan_report: "Regularly clean up test report",
timing_clean_api_report: "Regularly clean up api report",
timing_clean_load_report: "Regularly clean up performance report",

View File

@ -879,6 +879,34 @@ export default {
compare: '对比',
change_latest_tip: '此操作会修改接口,场景,测试用例等列表页面的默认展示,可能会消耗一些时间。请耐心等待!'
},
project_file: {
file_module_type: {
module: '模块',
repository: '存储库'
},
file: {
branch: '文件分支',
path: '文件路径',
},
repository: {
name: '存储库名称',
path: '存储库地址',
token: 'Token',
desc: '描述',
version_history: '版本历史',
file_version: '文件版本',
update_log: '更新记录',
},
validation: {
input_repository_name: '请输入存储库名称',
input_repository_path: '请输入存储库地址',
input_repository_token: '请输入存储库Token',
input_file_branch: '请输入文件分支',
input_file_path: '请输入文件路径',
input_gitee_user_please: 'Gitee用户需要输入用户名',
can_not_move_repository_file: '文件库文件无法移动',
},
},
timing_clean_plan_report: "定时清理测试计划报告",
timing_clean_api_report: "定时清理接口测试报告",
timing_clean_load_report: "定时清理性能测试报告",

View File

@ -875,6 +875,34 @@ export default {
compare: '對比',
change_latest_tip: '此操作會修改接口,場景,測試用例等列表頁面的默認展示,可能會消耗一些時間。請耐心等待! '
},
project_file: {
file_module_type: {
module: '模塊',
repository: '存儲庫'
},
repository: {
name: '存儲庫名稱',
path: '存儲庫地址',
token: 'Token',
desc: '描述',
version_history: '版本歷史',
file_version: '文件版本',
update_log: '更新記錄',
},
file: {
branch: '文件分支',
path: '文件路徑',
},
validation: {
input_repository_name: '請輸入存儲庫名稱',
input_repository_path: '請輸入存儲庫地址',
input_repository_token: '請輸入存儲庫Token',
input_file_branch: '请输入文件分支',
input_file_path: '请输入文件路徑',
input_gitee_user_please: 'Gitee用戶需要輸入用戶名',
can_not_move_repository_file: '文件庫文件無法移動',
},
},
timing_clean_plan_report: "定時清理測試計劃報告",
timing_clean_api_report: "定時清理接口測試報告",
timing_clean_load_report: "定時清理性能測試報告",