feat(项目设置): 文件库下载文件功能开发

This commit is contained in:
song-tianyang 2023-11-06 18:21:08 +08:00 committed by 刘瑞斌
parent a893e1293d
commit 72f1d1abd1
14 changed files with 318 additions and 101 deletions

View File

@ -76,7 +76,7 @@ public class FileManagementController {
@GetMapping(value = "/download/{id}")
@Operation(summary = "项目管理-文件管理-下载文件")
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_DOWNLOAD)
public ResponseEntity<byte[]> download(@PathVariable String id) {
public ResponseEntity<byte[]> download(@PathVariable String id) throws Exception {
return fileMetadataService.downloadById(id);
}

View File

@ -28,32 +28,28 @@ public class FilePreviewController {
@GetMapping(value = "/original/{userId}/{fileId}")
@Operation(summary = "预览原图")
public ResponseEntity<byte[]> originalImg(@PathVariable String userId,@PathVariable String fileId) {
public ResponseEntity<byte[]> originalImg(@PathVariable String userId, @PathVariable String fileId) throws Exception {
FileInformationResponse fileInformationResponse = fileMetadataService.get(fileId);
if (StringUtils.isEmpty(fileInformationResponse.getId())) {
throw new MSException("file.not.exist");
}
//检查权限
if (permissionCheckService.userHasProjectPermission(userId, fileInformationResponse.getProjectId(), PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_DOWNLOAD)) {
return fileMetadataService.downloadById(fileId);
}else {
if (!permissionCheckService.userHasProjectPermission(userId, fileInformationResponse.getProjectId(), PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_DOWNLOAD)) {
throw new MSException("http_result_forbidden");
}
return fileMetadataService.downloadById(fileId);
}
@GetMapping(value = "/compressed/{userId}/{fileId}")
@Operation(summary = "预览缩略图")
public ResponseEntity<byte[]> compressedImg(@PathVariable String userId,@PathVariable String fileId) {
public ResponseEntity<byte[]> compressedImg(@PathVariable String userId, @PathVariable String fileId) throws Exception {
FileInformationResponse fileInformationResponse = fileMetadataService.get(fileId);
if (StringUtils.isEmpty(fileInformationResponse.getId())) {
throw new MSException("file.not.exist");
}
//检查权限
if (permissionCheckService.userHasProjectPermission(userId, fileInformationResponse.getProjectId(), PermissionConstants.PROJECT_FILE_MANAGEMENT_READ)) {
return fileMetadataService.downloadPreviewImgById(fileId);
}else {
if (!permissionCheckService.userHasProjectPermission(userId, fileInformationResponse.getProjectId(), PermissionConstants.PROJECT_FILE_MANAGEMENT_READ)) {
throw new MSException("http_result_forbidden");
}
return fileMetadataService.downloadPreviewImgById(fileId);
}
}

View File

@ -36,7 +36,6 @@ public class FileRepositoryController {
return fileRepositoryService.getTree(projectId);
}
@GetMapping(value = "/file-type/{projectId}")
@Operation(summary = "项目管理-文件管理-存储库-获取已存在的存储库文件类型")
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ)

View File

@ -2,11 +2,13 @@ package io.metersphere.project.service;
import io.metersphere.project.domain.FileMetadata;
import io.metersphere.project.domain.FileMetadataExample;
import io.metersphere.project.domain.FileMetadataRepositoryExample;
import io.metersphere.project.domain.FileModuleExample;
import io.metersphere.project.dto.filemanagement.FileManagementQuery;
import io.metersphere.project.dto.filemanagement.request.FileBatchProcessRequest;
import io.metersphere.project.mapper.ExtFileMetadataMapper;
import io.metersphere.project.mapper.FileMetadataMapper;
import io.metersphere.project.mapper.FileMetadataRepositoryMapper;
import io.metersphere.project.mapper.FileModuleMapper;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.exception.MSException;
@ -28,6 +30,8 @@ public class FileManagementService {
@Resource
private FileMetadataMapper fileMetadataMapper;
@Resource
private FileMetadataRepositoryMapper fileMetadataRepositoryMapper;
@Resource
private FileModuleMapper fileModuleMapper;
@Resource
private FileService fileService;
@ -54,6 +58,10 @@ public class FileManagementService {
example.createCriteria().andIdIn(deleteIds);
fileMetadataMapper.deleteByExample(example);
FileMetadataRepositoryExample repositoryExample = new FileMetadataRepositoryExample();
repositoryExample.createCriteria().andFileMetadataIdIn(deleteIds);
fileMetadataRepositoryMapper.deleteByExample(repositoryExample);
//记录日志
fileMetadataLogService.saveDeleteLog(deleteList, request.getProjectId(), operator);

View File

@ -145,10 +145,9 @@ public class FileMetadataLogService {
public void saveRepositoryAddLog(FileMetadata fileMetadata, FileMetadataRepository repositoryFile, String operator) {
Project project = projectMapper.selectByPrimaryKey(fileMetadata.getProjectId());
Map<String, Object> logContent = new HashMap<>() {{
this.put("fileMetadata", fileMetadata);
this.put("repositoryFile", repositoryFile);
}};
Map<String, Object> logContent = new HashMap<>();
logContent.put("fileMetadata", fileMetadata);
logContent.put("repositoryFile", repositoryFile);
LogDTO dto = LogDTOBuilder.builder()
.projectId(fileMetadata.getProjectId())
.organizationId(project.getOrganizationId())

View File

@ -4,12 +4,16 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.project.domain.FileMetadata;
import io.metersphere.project.domain.FileMetadataExample;
import io.metersphere.project.domain.FileMetadataRepository;
import io.metersphere.project.domain.FileModuleRepository;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.filemanagement.FileManagementQuery;
import io.metersphere.project.dto.filemanagement.request.*;
import io.metersphere.project.dto.filemanagement.response.FileInformationResponse;
import io.metersphere.project.mapper.ExtFileMetadataMapper;
import io.metersphere.project.mapper.FileMetadataMapper;
import io.metersphere.project.mapper.FileMetadataRepositoryMapper;
import io.metersphere.project.mapper.FileModuleRepositoryMapper;
import io.metersphere.project.utils.FileDownloadUtils;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.constants.StorageType;
@ -50,6 +54,10 @@ public class FileMetadataService {
@Resource
private ExtFileMetadataMapper extFileMetadataMapper;
@Resource
private FileMetadataRepositoryMapper fileMetadataRepositoryMapper;
@Resource
private FileModuleRepositoryMapper fileModuleRepositoryMapper;
@Resource
private FileMetadataLogService fileMetadataLogService;
@Resource
private FileManagementService fileManagementService;
@ -106,7 +114,7 @@ public class FileMetadataService {
}
}
public FileMetadata saveFileMetadata(String projectId, String moduleId, String filePath, String operator, long size, boolean enable) {
public FileMetadata saveFileMetadata(String projectId, String moduleId, String filePath, String storage, String operator, long size, boolean enable) {
String fileName = TempFileUtils.getFileNameByPath(filePath);
FileMetadata fileMetadata = new FileMetadata();
if (StringUtils.lastIndexOf(fileName, ".") > 0) {
@ -125,7 +133,7 @@ public class FileMetadataService {
this.checkFileName(null, fileMetadata.getName(), projectId);
fileMetadata.setId(IDGenerator.nextStr());
fileMetadata.setStorage(StorageType.MINIO.name());
fileMetadata.setStorage(storage);
fileMetadata.setProjectId(projectId);
fileMetadata.setModuleId(moduleId);
long operationTime = System.currentTimeMillis();
@ -148,7 +156,7 @@ public class FileMetadataService {
String fileName = StringUtils.trim(uploadFile.getOriginalFilename());
FileMetadata fileMetadata = this.saveFileMetadata(request.getProjectId(), request.getModuleId(), fileName, operator, uploadFile.getSize(), request.isEnable());
FileMetadata fileMetadata = this.saveFileMetadata(request.getProjectId(), request.getModuleId(), fileName, StorageType.MINIO.name(), operator, uploadFile.getSize(), request.isEnable());
//记录日志
fileMetadataLogService.saveUploadLog(fileMetadata, operator);
@ -189,7 +197,7 @@ public class FileMetadataService {
return fileService.upload(file, uploadFileRequest);
}
public ResponseEntity<byte[]> downloadById(String id) {
public ResponseEntity<byte[]> downloadById(String id) throws Exception {
FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(id);
byte[] bytes = this.getFile(fileMetadata);
@ -206,7 +214,7 @@ public class FileMetadataService {
return fileName + "." + type;
}
private byte[] getFile(FileMetadata fileMetadata) {
private byte[] getFile(FileMetadata fileMetadata) throws Exception {
if (fileMetadata == null) {
throw new MSException(Translator.get("file.not.exist"));
}
@ -214,12 +222,15 @@ public class FileMetadataService {
fileRequest.setFileName(fileMetadata.getId());
fileRequest.setProjectId(fileMetadata.getProjectId());
fileRequest.setStorage(fileMetadata.getStorage());
try {
return fileService.download(fileRequest);
} catch (Exception e) {
LogUtils.error("获取文件失败", e);
//获取git文件下载
if (StringUtils.equals(fileMetadata.getStorage(), StorageType.GIT.name())) {
FileModuleRepository fileModuleRepository = fileModuleRepositoryMapper.selectByPrimaryKey(fileMetadata.getModuleId());
FileMetadataRepository fileMetadataRepository = fileMetadataRepositoryMapper.selectByPrimaryKey(fileMetadata.getId());
fileRequest.setGitFileRequest(fileModuleRepository, fileMetadataRepository);
}
return new byte[0];
return fileService.download(fileRequest);
}
public void update(FileUpdateRequest request, String operator) {
@ -281,9 +292,14 @@ public class FileMetadataService {
public byte[] batchDownload(List<FileMetadata> fileMetadataList) {
Map<String, byte[]> files = new LinkedHashMap<>();
fileMetadataList.forEach(fileMetadata -> {
byte[] bytes = this.getFile(fileMetadata);
if (bytes != null) {
files.put(this.getFileName(fileMetadata.getName(), fileMetadata.getType()), bytes);
byte[] bytes;
try {
bytes = this.getFile(fileMetadata);
if (bytes != null) {
files.put(this.getFileName(fileMetadata.getName(), fileMetadata.getType()), bytes);
}
} catch (Exception e) {
LogUtils.error("下载文件失败", e);
}
});
@ -371,7 +387,7 @@ public class FileMetadataService {
return moduleCountMap;
}
public ResponseEntity<byte[]> downloadPreviewImgById(String id) {
public ResponseEntity<byte[]> downloadPreviewImgById(String id) throws Exception {
FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(id);
String previewImgPath = null;
if (TempFileUtils.isImage(fileMetadata.getType())) {

View File

@ -2,12 +2,14 @@ package io.metersphere.project.service;
import io.metersphere.project.domain.FileModule;
import io.metersphere.project.domain.FileModuleExample;
import io.metersphere.project.domain.FileModuleRepositoryExample;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.NodeSortDTO;
import io.metersphere.project.dto.filemanagement.request.FileModuleCreateRequest;
import io.metersphere.project.dto.filemanagement.request.FileModuleUpdateRequest;
import io.metersphere.project.mapper.ExtFileModuleMapper;
import io.metersphere.project.mapper.FileModuleMapper;
import io.metersphere.project.mapper.FileModuleRepositoryMapper;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.Translator;
@ -37,6 +39,8 @@ public class FileModuleService extends ModuleTreeService implements CleanupProje
@Resource
protected FileModuleLogService fileModuleLogService;
@Resource
private FileModuleRepositoryMapper fileModuleRepositoryMapper;
@Resource
protected FileModuleMapper fileModuleMapper;
@Resource
protected ExtFileModuleMapper extFileModuleMapper;
@ -139,12 +143,22 @@ public class FileModuleService extends ModuleTreeService implements CleanupProje
//记录日志
fileModuleLogService.saveDeleteLog(deleteModule, currentUser);
}
FileModuleRepositoryExample repositoryExample = new FileModuleRepositoryExample();
repositoryExample.createCriteria().andFileModuleIdEqualTo(deleteId);
fileModuleRepositoryMapper.deleteByExample(repositoryExample);
}
public void deleteModule(List<String> deleteIds) {
if (CollectionUtils.isEmpty(deleteIds)) {
return;
}
extFileModuleMapper.deleteByIds(deleteIds);
FileModuleRepositoryExample repositoryExample = new FileModuleRepositoryExample();
repositoryExample.createCriteria().andFileModuleIdIn(deleteIds);
fileModuleRepositoryMapper.deleteByExample(repositoryExample);
fileManagementService.deleteByModuleIds(deleteIds);
List<String> childrenIds = extFileModuleMapper.selectChildrenIdsByParentIds(deleteIds);

View File

@ -10,13 +10,14 @@ import io.metersphere.project.dto.filemanagement.request.FileRepositoryUpdateReq
import io.metersphere.project.dto.filemanagement.request.RepositoryFileAddRequest;
import io.metersphere.project.mapper.FileMetadataRepositoryMapper;
import io.metersphere.project.mapper.FileModuleRepositoryMapper;
import io.metersphere.project.utils.GitRepositoryUtil;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.constants.StorageType;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.RemoteFileAttachInfo;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.utils.GitRepositoryUtil;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
@ -59,7 +60,7 @@ public class FileRepositoryService extends FileModuleService {
fileModule.setPos(this.countPos(ModuleConstants.ROOT_NODE_PARENT_ID, ModuleConstants.NODE_TYPE_GIT));
fileModule.setCreateUser(operator);
fileModule.setUpdateUser(operator);
fileModule.setModuleType(ModuleConstants.NODE_TYPE_DEFAULT);
fileModule.setModuleType(ModuleConstants.NODE_TYPE_GIT);
fileModuleMapper.insert(fileModule);
//记录模块仓库数据
@ -137,7 +138,7 @@ public class FileRepositoryService extends FileModuleService {
}
FileMetadata fileMetadata = fileMetadataService.saveFileMetadata(
fileModule.getProjectId(), fileModule.getId(), request.getFilePath(), operator, fileAttachInfo.getSize(), request.isEnable());
fileModule.getProjectId(), fileModule.getId(), request.getFilePath(), StorageType.GIT.name(), operator, fileAttachInfo.getSize(), request.isEnable());
FileMetadataRepository fileMetadataRepository = new FileMetadataRepository();
fileMetadataRepository.setFileMetadataId(fileMetadata.getId());
fileMetadataRepository.setBranch(fileAttachInfo.getBranch());

View File

@ -1,16 +1,12 @@
package io.metersphere.project.controller.filemanagement;
import io.metersphere.project.domain.FileMetadata;
import io.metersphere.project.domain.FileMetadataRepository;
import io.metersphere.project.domain.FileModule;
import io.metersphere.project.domain.FileModuleRepository;
import io.metersphere.project.domain.*;
import io.metersphere.project.dto.filemanagement.request.*;
import io.metersphere.project.dto.filemanagement.response.FileInformationResponse;
import io.metersphere.project.mapper.FileMetadataMapper;
import io.metersphere.project.mapper.FileMetadataRepositoryMapper;
import io.metersphere.project.mapper.FileModuleMapper;
import io.metersphere.project.mapper.FileModuleRepositoryMapper;
import io.metersphere.project.service.FileModuleService;
import io.metersphere.project.utils.FileManagementRequestUtils;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.constants.PermissionConstants;
@ -27,15 +23,20 @@ import io.metersphere.system.service.CommonProjectService;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ -49,19 +50,11 @@ public class FileRepositoryControllerTest extends BaseTest {
private static final String GITEE_USERNAME = "testformetersphere";
private static final String GITEE_TOKEN = "4548d369bb595738d726512742e4478f";
private static List<BaseTreeNode> repositoryTreeNodes = new ArrayList<>();
private static final Map<String, String> FILE_ID_PATH = new LinkedHashMap<>();
private static final Map<String, String> FILE_VERSIONS_ID_MAP = new HashMap<>();
private static String reUploadFileId;
private static final List<String> fileList = new ArrayList<>();
private static String repositoryId;
private static String jarFileId;
private static String picFileId;
@Resource
private FileModuleService fileModuleService;
@Resource
private FileModuleMapper fileModuleMapper;
@Resource
@ -309,6 +302,43 @@ public class FileRepositoryControllerTest extends BaseTest {
this.requestPost(FileManagementRequestUtils.URL_FILE_REPOSITORY_UPDATE, createRequest).andExpect(status().is5xxServerError());
}
@Test
@Order(5)
public void moduleDeleteTest() throws Exception {
if (StringUtils.isEmpty(repositoryId)) {
this.moduleAddTest();
}
this.requestGetWithOk(String.format(FileManagementRequestUtils.URL_MODULE_DELETE, repositoryId));
this.checkRepositoryDeleted(repositoryId);
checkLog(repositoryId, OperationLogType.DELETE, FileManagementRequestUtils.URL_MODULE_DELETE);
//重新添加
this.moduleAddTest();
}
private void checkRepositoryDeleted(String repositoryId) {
FileModuleRepositoryExample repositoryExample = new FileModuleRepositoryExample();
repositoryExample.createCriteria().andFileModuleIdEqualTo(repositoryId);
Assertions.assertEquals(fileModuleRepositoryMapper.countByExample(repositoryExample), 0);
FileModuleExample example = new FileModuleExample();
example.createCriteria().andIdEqualTo(repositoryId);
Assertions.assertEquals(fileModuleMapper.countByExample(example), 0);
}
private void checkRepositoryFileDeleted(String fileId) {
FileMetadataRepositoryExample repositoryExample = new FileMetadataRepositoryExample();
repositoryExample.createCriteria().andFileMetadataIdEqualTo(fileId);
Assertions.assertEquals(fileMetadataRepositoryMapper.countByExample(repositoryExample), 0);
FileMetadataExample example = new FileMetadataExample();
example.createCriteria().andIdEqualTo(fileId);
Assertions.assertEquals(fileMetadataMapper.countByExample(example), 0);
}
@Test
@Order(10)
public void repositoryListTest() throws Exception {
@ -333,6 +363,8 @@ public class FileRepositoryControllerTest extends BaseTest {
MvcResult result = this.requestPostWithOkAndReturn(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request);
String fileId = JSON.parseObject(result.getResponse().getContentAsString(), ResultHolder.class).getData().toString();
this.checkFileRepositoryFile(fileId, request);
this.checkLog(fileId, OperationLogType.ADD, FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD);
fileList.add(fileId);
//测试其他分支的多层目录的文件
String otherBranch = "develop";
String folderFilePath1 = "test-folder/gitee/test.txt";
@ -343,7 +375,7 @@ public class FileRepositoryControllerTest extends BaseTest {
result = this.requestPostWithOkAndReturn(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request);
fileId = JSON.parseObject(result.getResponse().getContentAsString(), ResultHolder.class).getData().toString();
this.checkFileRepositoryFile(fileId, request);
fileList.add(fileId);
//测试隐藏文件
String folderFilePath2 = "test-folder/.keep";
request = new RepositoryFileAddRequest();
@ -353,7 +385,7 @@ public class FileRepositoryControllerTest extends BaseTest {
result = this.requestPostWithOkAndReturn(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request);
fileId = JSON.parseObject(result.getResponse().getContentAsString(), ResultHolder.class).getData().toString();
this.checkFileRepositoryFile(fileId, request);
fileList.add(fileId);
//测试添加jar包并且启用
request = new RepositoryFileAddRequest();
request.setBranch(branch);
@ -363,7 +395,17 @@ public class FileRepositoryControllerTest extends BaseTest {
result = this.requestPostWithOkAndReturn(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request);
fileId = JSON.parseObject(result.getResponse().getContentAsString(), ResultHolder.class).getData().toString();
this.checkFileRepositoryFile(fileId, request);
fileList.add(fileId);
//获取图片信息
request = new RepositoryFileAddRequest();
request.setBranch(otherBranch);
request.setFilePath("1095388459180046.jpg");
request.setModuleId(repositoryId);
result = this.requestPostWithOkAndReturn(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request);
fileId = JSON.parseObject(result.getResponse().getContentAsString(), ResultHolder.class).getData().toString();
this.checkFileRepositoryFile(fileId, request);
this.picFileId = fileId;
fileList.add(fileId);
{
//重复添加测试
request = new RepositoryFileAddRequest();
@ -418,11 +460,28 @@ public class FileRepositoryControllerTest extends BaseTest {
request.setBranch(IDGenerator.nextStr());
request.setFilePath(folderFilePath2);
this.requestPost(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request).andExpect(status().isBadRequest());
}
}
@Test
@Order(12)
public void repositoryGetFileTest() throws Exception {
if (StringUtils.isEmpty(picFileId)) {
this.repositoryAddFileTest();
}
//下载文件
MvcResult originalResult = this.downloadFile(String.format(FileManagementRequestUtils.URL_FILE_PREVIEW_ORIGINAL, "admin", picFileId));
byte[] fileBytes = originalResult.getResponse().getContentAsByteArray();
Assertions.assertTrue(fileBytes.length > 0);
//预览文件
originalResult = this.downloadFile(String.format(FileManagementRequestUtils.URL_FILE_PREVIEW_ORIGINAL, "admin", picFileId));
Assertions.assertTrue(originalResult.getResponse().getContentAsByteArray().length > 0);
MvcResult compressedResult = this.downloadFile(String.format(FileManagementRequestUtils.URL_FILE_PREVIEW_COMPRESSED, "admin", picFileId));
Assertions.assertTrue(compressedResult.getResponse().getContentAsByteArray().length > 0);
}
private void checkFileRepositoryFile(String fileId, RepositoryFileAddRequest request) {
FileMetadataRepository repository = fileMetadataRepositoryMapper.selectByPrimaryKey(fileId);
Assertions.assertEquals(repository.getBranch(), request.getBranch());
@ -430,6 +489,13 @@ public class FileRepositoryControllerTest extends BaseTest {
Assertions.assertNotNull(repository.getCommitMessage());
FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId);
Assertions.assertEquals(fileMetadata.getPath(), request.getFilePath());
Assertions.assertEquals(fileMetadata.getStorage(), StorageType.GIT.name());
}
protected MvcResult downloadFile(String url, Object... uriVariables) throws Exception {
return mockMvc.perform(getRequestBuilder(url, uriVariables))
.andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM_VALUE))
.andExpect(status().isOk()).andReturn();
}
@Test
@ -440,9 +506,27 @@ public class FileRepositoryControllerTest extends BaseTest {
this.requestGetPermissionTest(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ, String.format(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_TYPE, DEFAULT_PROJECT_ID));
}
@Test
@Order(99)
public void repositoryFileDeleteTest() throws Exception {
if (CollectionUtils.isEmpty(fileList)) {
this.repositoryAddFileTest();
}
FileBatchProcessRequest fileBatchProcessRequest = new FileBatchProcessRequest();
fileBatchProcessRequest.setProjectId(project.getId());
fileBatchProcessRequest.setSelectIds(fileList);
this.requestPostWithOk(FileManagementRequestUtils.URL_FILE_DELETE, fileBatchProcessRequest);
for (String fileId : fileList) {
this.checkLog(fileId, OperationLogType.DELETE, FileManagementRequestUtils.URL_FILE_DELETE);
this.checkRepositoryFileDeleted(fileId);
}
}
private void checkFileRepository(String repositoryId, String projectId, String name, String platform, String url, String token, String userName) {
FileModule module = fileModuleMapper.selectByPrimaryKey(repositoryId);
FileModuleRepository repository = fileModuleRepositoryMapper.selectByPrimaryKey(repositoryId);
Assertions.assertEquals(module.getModuleType(), ModuleConstants.NODE_TYPE_GIT);
if (StringUtils.isNotEmpty(projectId)) {
Assertions.assertEquals(module.getProjectId(), projectId);
}

View File

@ -12,6 +12,7 @@ public class FileCenter {
Map<StorageType, FileRepository> repositoryMap = new HashMap<>() {{
put(StorageType.MINIO, CommonBeanFactory.getBean(MinioRepository.class));
put(StorageType.LOCAL, CommonBeanFactory.getBean(LocalFileRepository.class));
put(StorageType.GIT, CommonBeanFactory.getBean(GitRepository.class));
}};
FileRepository fileRepository = repositoryMap.get(storageType);
return fileRepository == null ? getDefaultRepository() : fileRepository;

View File

@ -1,5 +1,8 @@
package io.metersphere.system.file;
import io.metersphere.project.domain.FileMetadataRepository;
import io.metersphere.project.domain.FileModuleRepository;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@ -15,4 +18,21 @@ public class FileRequest {
// 文件名称
private String fileName;
//Git文件信息
private GitFileRequest gitFileRequest;
public void setGitFileRequest(FileModuleRepository repository, FileMetadataRepository file) {
gitFileRequest = new GitFileRequest(repository.getUrl(), repository.getToken(), repository.getUserName(), file.getBranch(), file.getCommitId());
}
}
@Data
@AllArgsConstructor
class GitFileRequest {
private String url;
private String token;
private String userName;
private String branch;
private String commitId;
}

View File

@ -0,0 +1,78 @@
package io.metersphere.system.file;
import io.metersphere.system.utils.GitRepositoryUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
@Component
public class GitRepository implements FileRepository {
@Override
public String saveFile(MultipartFile file, FileRequest request) throws Exception {
return null;
}
@Override
public String saveFile(byte[] bytes, FileRequest request) throws Exception {
return null;
}
@Override
public String saveFile(InputStream inputStream, FileRequest request) throws Exception {
return null;
}
@Override
public void delete(FileRequest request) throws Exception {
}
@Override
public void deleteFolder(FileRequest request) throws Exception {
}
@Override
public byte[] getFile(FileRequest request) throws Exception {
byte[] fileBytes = new byte[0];
if (request.getGitFileRequest() != null) {
GitFileRequest gitFileInfo = request.getGitFileRequest();
GitRepositoryUtil repositoryUtils = new GitRepositoryUtil(
gitFileInfo.getUrl(), gitFileInfo.getUserName(), gitFileInfo.getToken());
fileBytes = repositoryUtils.getFile(gitFileInfo.getUrl(), gitFileInfo.getCommitId());
}
return fileBytes;
}
@Override
public InputStream getFileAsStream(FileRequest request) throws Exception {
return new ByteArrayInputStream(getFile(request));
}
// 缓冲区大小
private static final int BUFFER_SIZE = 8192;
@Override
public void downloadFile(FileRequest request, String fullPath) throws Exception {
// 下载对象到本地文件
try (InputStream inputStream = getFileAsStream(request);
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(fullPath))) {
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
}
@Override
public List<String> getFolderFileNames(FileRequest request) throws Exception {
return null;
}
}

View File

@ -1,7 +1,9 @@
package io.metersphere.project.utils;
package io.metersphere.system.utils;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.dto.RepositoryQuery;
import io.metersphere.system.dto.sdk.RemoteFileAttachInfo;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
@ -19,9 +21,8 @@ import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
public class GitRepositoryUtil {
private final String REF_SPACE = "+refs/heads/*:refs/heads/*";
@ -46,40 +47,40 @@ public class GitRepositoryUtil {
//以下方法先注释掉用到了再打开
// public byte[] getSingleFile(String filePath, String commitId) throws Exception {
// LogUtils.info("准备获取文件. repositoryUrl" + repositoryUrl + "; filePath" + filePath + "; commitId" + commitId);
// InMemoryRepository repo = this.getGitRepositoryInMemory(repositoryUrl, userName, token);
// ObjectId fileCommitObjectId = repo.resolve(commitId);
// ObjectId objectId = this.getTreeWork(repo, fileCommitObjectId, filePath).getObjectId(0);
// ObjectLoader loader = repo.open(objectId);
// byte[] returnBytes = loader.getBytes();
// this.closeConnection(repo);
// return returnBytes;
// }
public byte[] getFile(String filePath, String commitId) throws Exception {
LogUtils.info("准备获取文件. repositoryUrl" + repositoryUrl + "; filePath" + filePath + "; commitId" + commitId);
InMemoryRepository repo = this.getGitRepositoryInMemory(repositoryUrl, userName, token);
ObjectId fileCommitObjectId = repo.resolve(commitId);
ObjectId objectId = this.getTreeWork(repo, fileCommitObjectId, filePath).getObjectId(0);
ObjectLoader loader = repo.open(objectId);
byte[] returnBytes = loader.getBytes();
this.closeConnection(repo);
return returnBytes;
}
// public Map<String, byte[]> getFiles(List<RepositoryQuery> RepositoryQueryList) throws Exception {
// Map<String, byte[]> returnMap = new HashMap<>();
// if (CollectionUtils.isEmpty(RepositoryQueryList)) {
// return returnMap;
// }
// Map<String, List<RepositoryQuery>> commitIdFilePathMap = RepositoryQueryList.stream().collect(Collectors.groupingBy(RepositoryQuery::getCommitId));
// InMemoryRepository repo = this.getGitRepositoryInMemory(repositoryUrl, userName, token);
// ObjectId fileCommitObjectId;
// for (Map.Entry<String, List<RepositoryQuery>> commitFilePathEntry : commitIdFilePathMap.entrySet()) {
// String commitId = commitFilePathEntry.getKey();
// List<RepositoryQuery> itemRequestList = commitFilePathEntry.getValue();
// for (RepositoryQuery RepositoryQuery : itemRequestList) {
// String filePath = RepositoryQuery.getFilePath();
// fileCommitObjectId = repo.resolve(commitId);
// ObjectId objectId = this.getTreeWork(repo, fileCommitObjectId, filePath).getObjectId(0);
// ObjectLoader loader = repo.open(objectId);
// returnMap.put(RepositoryQuery.getFileMetadataId(), loader.getBytes());
// }
// this.closeConnection(repo);
// }
// LogUtils.info("准备批量获取文件结束. repositoryUrl" + repositoryUrl);
// return returnMap;
// }
public Map<String, byte[]> getFiles(List<RepositoryQuery> RepositoryQueryList) throws Exception {
Map<String, byte[]> returnMap = new HashMap<>();
if (CollectionUtils.isEmpty(RepositoryQueryList)) {
return returnMap;
}
Map<String, List<RepositoryQuery>> commitIdFilePathMap = RepositoryQueryList.stream().collect(Collectors.groupingBy(RepositoryQuery::getCommitId));
InMemoryRepository repo = this.getGitRepositoryInMemory(repositoryUrl, userName, token);
ObjectId fileCommitObjectId;
for (Map.Entry<String, List<RepositoryQuery>> commitFilePathEntry : commitIdFilePathMap.entrySet()) {
String commitId = commitFilePathEntry.getKey();
List<RepositoryQuery> itemRequestList = commitFilePathEntry.getValue();
for (RepositoryQuery repositoryQuery : itemRequestList) {
String filePath = repositoryQuery.getFilePath();
fileCommitObjectId = repo.resolve(commitId);
ObjectId objectId = this.getTreeWork(repo, fileCommitObjectId, filePath).getObjectId(0);
ObjectLoader loader = repo.open(objectId);
returnMap.put(repositoryQuery.getFileMetadataId(), loader.getBytes());
}
this.closeConnection(repo);
}
LogUtils.info("准备批量获取文件结束. repositoryUrl" + repositoryUrl);
return returnMap;
}
public RemoteFileAttachInfo selectLastCommitIdByBranch(String branch, String filePath) {
RemoteFileAttachInfo attachInfo;
@ -143,16 +144,16 @@ public class GitRepositoryUtil {
return repo;
}
// private TreeWalk getTreeWork(InMemoryRepository repo, ObjectId fileCommitObjectId, String filePath) throws Exception {
// 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));
// return treeWalk;
// }
private TreeWalk getTreeWork(InMemoryRepository repo, ObjectId fileCommitObjectId, String filePath) throws Exception {
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));
return treeWalk;
}
private void closeConnection(Repository repo) {
if (git != null) {