feat(项目设置): 添加文件库文件的功能开发

This commit is contained in:
song-tianyang 2023-11-06 16:08:29 +08:00 committed by 刘瑞斌
parent 013b37d409
commit a893e1293d
19 changed files with 353 additions and 303 deletions

View File

@ -20,16 +20,6 @@ public class FileMetadataRepository implements Serializable {
@Size(min = 1, max = 255, message = "{file_metadata_repository.branch.length_range}", groups = {Created.class, Updated.class})
private String branch;
@Schema(description = "存储库地址", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{file_metadata_repository.repository_url.not_blank}", groups = {Created.class})
@Size(min = 1, max = 255, message = "{file_metadata_repository.repository_url.length_range}", groups = {Created.class, Updated.class})
private String repositoryUrl;
@Schema(description = "token", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{file_metadata_repository.token.not_blank}", groups = {Created.class})
@Size(min = 1, max = 1000, message = "{file_metadata_repository.token.length_range}", groups = {Created.class, Updated.class})
private String token;
@Schema(description = "提交ID")
private String commitId;
@ -41,8 +31,6 @@ public class FileMetadataRepository implements Serializable {
public enum Column {
fileMetadataId("file_metadata_id", "fileMetadataId", "VARCHAR", false),
branch("branch", "branch", "VARCHAR", false),
repositoryUrl("repository_url", "repositoryUrl", "VARCHAR", false),
token("token", "token", "VARCHAR", false),
commitId("commit_id", "commitId", "VARCHAR", false),
commitMessage("commit_message", "commitMessage", "LONGVARCHAR", false);

View File

@ -244,146 +244,6 @@ public class FileMetadataRepositoryExample {
return (Criteria) this;
}
public Criteria andRepositoryUrlIsNull() {
addCriterion("repository_url is null");
return (Criteria) this;
}
public Criteria andRepositoryUrlIsNotNull() {
addCriterion("repository_url is not null");
return (Criteria) this;
}
public Criteria andRepositoryUrlEqualTo(String value) {
addCriterion("repository_url =", value, "repositoryUrl");
return (Criteria) this;
}
public Criteria andRepositoryUrlNotEqualTo(String value) {
addCriterion("repository_url <>", value, "repositoryUrl");
return (Criteria) this;
}
public Criteria andRepositoryUrlGreaterThan(String value) {
addCriterion("repository_url >", value, "repositoryUrl");
return (Criteria) this;
}
public Criteria andRepositoryUrlGreaterThanOrEqualTo(String value) {
addCriterion("repository_url >=", value, "repositoryUrl");
return (Criteria) this;
}
public Criteria andRepositoryUrlLessThan(String value) {
addCriterion("repository_url <", value, "repositoryUrl");
return (Criteria) this;
}
public Criteria andRepositoryUrlLessThanOrEqualTo(String value) {
addCriterion("repository_url <=", value, "repositoryUrl");
return (Criteria) this;
}
public Criteria andRepositoryUrlLike(String value) {
addCriterion("repository_url like", value, "repositoryUrl");
return (Criteria) this;
}
public Criteria andRepositoryUrlNotLike(String value) {
addCriterion("repository_url not like", value, "repositoryUrl");
return (Criteria) this;
}
public Criteria andRepositoryUrlIn(List<String> values) {
addCriterion("repository_url in", values, "repositoryUrl");
return (Criteria) this;
}
public Criteria andRepositoryUrlNotIn(List<String> values) {
addCriterion("repository_url not in", values, "repositoryUrl");
return (Criteria) this;
}
public Criteria andRepositoryUrlBetween(String value1, String value2) {
addCriterion("repository_url between", value1, value2, "repositoryUrl");
return (Criteria) this;
}
public Criteria andRepositoryUrlNotBetween(String value1, String value2) {
addCriterion("repository_url not between", value1, value2, "repositoryUrl");
return (Criteria) this;
}
public Criteria andTokenIsNull() {
addCriterion("token is null");
return (Criteria) this;
}
public Criteria andTokenIsNotNull() {
addCriterion("token is not null");
return (Criteria) this;
}
public Criteria andTokenEqualTo(String value) {
addCriterion("token =", value, "token");
return (Criteria) this;
}
public Criteria andTokenNotEqualTo(String value) {
addCriterion("token <>", value, "token");
return (Criteria) this;
}
public Criteria andTokenGreaterThan(String value) {
addCriterion("token >", value, "token");
return (Criteria) this;
}
public Criteria andTokenGreaterThanOrEqualTo(String value) {
addCriterion("token >=", value, "token");
return (Criteria) this;
}
public Criteria andTokenLessThan(String value) {
addCriterion("token <", value, "token");
return (Criteria) this;
}
public Criteria andTokenLessThanOrEqualTo(String value) {
addCriterion("token <=", value, "token");
return (Criteria) this;
}
public Criteria andTokenLike(String value) {
addCriterion("token like", value, "token");
return (Criteria) this;
}
public Criteria andTokenNotLike(String value) {
addCriterion("token not like", value, "token");
return (Criteria) this;
}
public Criteria andTokenIn(List<String> values) {
addCriterion("token in", values, "token");
return (Criteria) this;
}
public Criteria andTokenNotIn(List<String> values) {
addCriterion("token not in", values, "token");
return (Criteria) this;
}
public Criteria andTokenBetween(String value1, String value2) {
addCriterion("token between", value1, value2, "token");
return (Criteria) this;
}
public Criteria andTokenNotBetween(String value1, String value2) {
addCriterion("token not between", value1, value2, "token");
return (Criteria) this;
}
public Criteria andCommitIdIsNull() {
addCriterion("commit_id is null");
return (Criteria) this;

View File

@ -4,8 +4,6 @@
<resultMap id="BaseResultMap" type="io.metersphere.project.domain.FileMetadataRepository">
<id column="file_metadata_id" jdbcType="VARCHAR" property="fileMetadataId" />
<result column="branch" jdbcType="VARCHAR" property="branch" />
<result column="repository_url" jdbcType="VARCHAR" property="repositoryUrl" />
<result column="token" jdbcType="VARCHAR" property="token" />
<result column="commit_id" jdbcType="VARCHAR" property="commitId" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.project.domain.FileMetadataRepository">
@ -70,7 +68,7 @@
</where>
</sql>
<sql id="Base_Column_List">
file_metadata_id, branch, repository_url, token, commit_id
file_metadata_id, branch, commit_id
</sql>
<sql id="Blob_Column_List">
commit_message
@ -124,12 +122,10 @@
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.project.domain.FileMetadataRepository">
insert into file_metadata_repository (file_metadata_id, branch, repository_url,
token, commit_id, commit_message
)
values (#{fileMetadataId,jdbcType=VARCHAR}, #{branch,jdbcType=VARCHAR}, #{repositoryUrl,jdbcType=VARCHAR},
#{token,jdbcType=VARCHAR}, #{commitId,jdbcType=VARCHAR}, #{commitMessage,jdbcType=LONGVARCHAR}
)
insert into file_metadata_repository (file_metadata_id, branch, commit_id,
commit_message)
values (#{fileMetadataId,jdbcType=VARCHAR}, #{branch,jdbcType=VARCHAR}, #{commitId,jdbcType=VARCHAR},
#{commitMessage,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.project.domain.FileMetadataRepository">
insert into file_metadata_repository
@ -140,12 +136,6 @@
<if test="branch != null">
branch,
</if>
<if test="repositoryUrl != null">
repository_url,
</if>
<if test="token != null">
token,
</if>
<if test="commitId != null">
commit_id,
</if>
@ -160,12 +150,6 @@
<if test="branch != null">
#{branch,jdbcType=VARCHAR},
</if>
<if test="repositoryUrl != null">
#{repositoryUrl,jdbcType=VARCHAR},
</if>
<if test="token != null">
#{token,jdbcType=VARCHAR},
</if>
<if test="commitId != null">
#{commitId,jdbcType=VARCHAR},
</if>
@ -189,12 +173,6 @@
<if test="record.branch != null">
branch = #{record.branch,jdbcType=VARCHAR},
</if>
<if test="record.repositoryUrl != null">
repository_url = #{record.repositoryUrl,jdbcType=VARCHAR},
</if>
<if test="record.token != null">
token = #{record.token,jdbcType=VARCHAR},
</if>
<if test="record.commitId != null">
commit_id = #{record.commitId,jdbcType=VARCHAR},
</if>
@ -210,8 +188,6 @@
update file_metadata_repository
set file_metadata_id = #{record.fileMetadataId,jdbcType=VARCHAR},
branch = #{record.branch,jdbcType=VARCHAR},
repository_url = #{record.repositoryUrl,jdbcType=VARCHAR},
token = #{record.token,jdbcType=VARCHAR},
commit_id = #{record.commitId,jdbcType=VARCHAR},
commit_message = #{record.commitMessage,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
@ -222,8 +198,6 @@
update file_metadata_repository
set file_metadata_id = #{record.fileMetadataId,jdbcType=VARCHAR},
branch = #{record.branch,jdbcType=VARCHAR},
repository_url = #{record.repositoryUrl,jdbcType=VARCHAR},
token = #{record.token,jdbcType=VARCHAR},
commit_id = #{record.commitId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -235,12 +209,6 @@
<if test="branch != null">
branch = #{branch,jdbcType=VARCHAR},
</if>
<if test="repositoryUrl != null">
repository_url = #{repositoryUrl,jdbcType=VARCHAR},
</if>
<if test="token != null">
token = #{token,jdbcType=VARCHAR},
</if>
<if test="commitId != null">
commit_id = #{commitId,jdbcType=VARCHAR},
</if>
@ -253,8 +221,6 @@
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.project.domain.FileMetadataRepository">
update file_metadata_repository
set branch = #{branch,jdbcType=VARCHAR},
repository_url = #{repositoryUrl,jdbcType=VARCHAR},
token = #{token,jdbcType=VARCHAR},
commit_id = #{commitId,jdbcType=VARCHAR},
commit_message = #{commitMessage,jdbcType=LONGVARCHAR}
where file_metadata_id = #{fileMetadataId,jdbcType=VARCHAR}
@ -262,19 +228,16 @@
<update id="updateByPrimaryKey" parameterType="io.metersphere.project.domain.FileMetadataRepository">
update file_metadata_repository
set branch = #{branch,jdbcType=VARCHAR},
repository_url = #{repositoryUrl,jdbcType=VARCHAR},
token = #{token,jdbcType=VARCHAR},
commit_id = #{commitId,jdbcType=VARCHAR}
where file_metadata_id = #{fileMetadataId,jdbcType=VARCHAR}
</update>
<insert id="batchInsert" parameterType="map">
insert into file_metadata_repository
(file_metadata_id, branch, repository_url, token, commit_id, commit_message)
(file_metadata_id, branch, commit_id, commit_message)
values
<foreach collection="list" item="item" separator=",">
(#{item.fileMetadataId,jdbcType=VARCHAR}, #{item.branch,jdbcType=VARCHAR}, #{item.repositoryUrl,jdbcType=VARCHAR},
#{item.token,jdbcType=VARCHAR}, #{item.commitId,jdbcType=VARCHAR}, #{item.commitMessage,jdbcType=LONGVARCHAR}
)
(#{item.fileMetadataId,jdbcType=VARCHAR}, #{item.branch,jdbcType=VARCHAR}, #{item.commitId,jdbcType=VARCHAR},
#{item.commitMessage,jdbcType=LONGVARCHAR})
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
@ -293,12 +256,6 @@
<if test="'branch'.toString() == column.value">
#{item.branch,jdbcType=VARCHAR}
</if>
<if test="'repository_url'.toString() == column.value">
#{item.repositoryUrl,jdbcType=VARCHAR}
</if>
<if test="'token'.toString() == column.value">
#{item.token,jdbcType=VARCHAR}
</if>
<if test="'commit_id'.toString() == column.value">
#{item.commitId,jdbcType=VARCHAR}
</if>

View File

@ -66,8 +66,6 @@ CREATE TABLE IF NOT EXISTS file_metadata_repository
(
`file_metadata_id` VARCHAR(50) NOT NULL COMMENT '文件ID',
`branch` VARCHAR(255) NOT NULL COMMENT '分支',
`repository_url` VARCHAR(255) NOT NULL COMMENT '存储库地址',
`token` VARCHAR(1000) NOT NULL COMMENT 'token',
`commit_id` VARCHAR(255) COMMENT '提交ID',
`commit_message` TEXT COMMENT '提交信息',
PRIMARY KEY (file_metadata_id)

View File

@ -10,11 +10,11 @@ public class ModuleConstants {
//Git节点类型
public static final String NODE_TYPE_GIT = "git";
//GitHub节点类型
public static final String NODE_TYPE_GITHUB = "GitHub";
public static final String NODE_TYPE_GITHUB = "Github";
//Gitee节点类型
public static final String NODE_TYPE_GITEE = "Gitee";
//GitLab节点类型
public static final String NODE_TYPE_GITLAB = "GitLab";
public static final String NODE_TYPE_GITLAB = "Gitlab";
public static final String NODE_PROTOCOL_HTTP = "HTTP";
}

View File

@ -17,6 +17,14 @@ public class TempFileUtils {
return StringUtils.equalsAnyIgnoreCase(type, "jpg", "jpeg", "png", "gif", "bmp", "svg", "ico");
}
public static String getFileNameByPath(String filePath) {
if (StringUtils.contains(filePath, "/")) {
return StringUtils.substringAfterLast(filePath, "/");
} else {
return filePath;
}
}
public static String getImgFileTmpPath(String fileId) {
return TEMP_FILE_FOLDER + fileId + ".jpg";

View File

@ -19,13 +19,15 @@ file_module.project_id.length_range=项目ID长度必须在{min}-{max}之间
file_module.project_id.not_blank=项目ID不能为空
file_module.name.length_range=名称长度必须在{min}-{max}之间
file_module.name.not_blank=名称不能为空
file_repository.not.exist=存储库不存在
file_repository.connect.error=存储库链接失败
file_repository.platform.error=存储库类型不正确
file_repository.id.not_blank=存储库ID不能为空
file_repository.name.not_blank=存储库名称不能为空
file_repository.type.not_blank=存储库类型不能为空
file_repository.token.not_blank=存储库token不能为空
file_repository.url.not_blank=存储库地址不能为空
file_repository.branch.not_blank=存储库分支不能为空
file_repository.file_path.not_blank=存储库文件路径不能为空
custom_field_template.id.not_blank=ID不能为空
custom_field_template.field_id.length_range=字段ID长度必须在{min}-{max}之间
custom_field_template.field_id.not_blank=字段ID不能为空
@ -440,6 +442,7 @@ file.log.change_file_module=文件进行了移动
file.log.next=之后
file.log.previous=之前
file.log.upload=上传
file.log.repository.add=添加了存储库文件
file.log.re-upload=重新上传
file.name.cannot.be.empty=文件名称不能为空
#file management over

View File

@ -31,13 +31,15 @@ file_module.project_id.length_range=Project ID length must be between {min} and
file_module.project_id.not_blank=Project ID is required
file_module.name.length_range=Name length must be between {min} and {max}
file_module.name.not_blank=Name is required
file_repository.not.exist=Repository not exist
file_repository.connect.error=Repository connect error
file_repository.platform.error=Repository platform error
file_repository.id.not_blank=Repository ID is required
file_repository.name.not_blank=Repository name is required
file_repository.type.not_blank=Repository type is required
file_repository.token.not_blank=Repository token is required
file_repository.url.not_blank=Repository url is required
file_repository.branch.not_blank=Repository branch is required
file_repository.file_path.not_blank=Repository file path is required
custom_field_template.id.not_blank=ID is required
custom_field_template.field_id.length_range=Field ID length must be between {min} and {max}
custom_field_template.field_id.not_blank=Field ID is required
@ -476,6 +478,7 @@ file.log.change_file_module=File has be moved
file.log.next=next
file.log.previous=behind
file.log.upload=upload
file.log.repository.add=Add repository file
file.log.re-upload=re-upload
file.name.cannot.be.empty=File name cannot be empty
#file management over

View File

@ -31,13 +31,15 @@ file_module.project_id.length_range=项目ID长度必须在{min}-{max}之间
file_module.project_id.not_blank=项目ID不能为空
file_module.name.length_range=名称长度必须在{min}-{max}之间
file_module.name.not_blank=名称不能为空
file_repository.not.exist=存储库不存在
file_repository.connect.error=存储库链接失败
file_repository.platform.error=存储库类型不正确
file_repository.id.not_blank=存储库ID不能为空
file_repository.name.not_blank=存储库名称不能为空
file_repository.type.not_blank=存储库类型不能为空
file_repository.token.not_blank=存储库token不能为空
file_repository.url.not_blank=存储库地址不能为空
file_repository.branch.not_blank=存储库分支不能为空
file_repository.file_path.not_blank=存储库文件路径不能为空
custom_field_template.id.not_blank=ID不能为空
custom_field_template.field_id.length_range=字段ID长度必须在{min}-{max}之间
custom_field_template.field_id.not_blank=字段ID不能为空
@ -475,6 +477,7 @@ file.log.change_file_module=文件进行了移动
file.log.next=之后
file.log.previous=之前
file.log.upload=上传
file.log.repository.add=添加了存储库文件
file.log.re-upload=重新上传
file.name.cannot.be.empty=文件名称不能为空
#file management over

View File

@ -31,13 +31,15 @@ file_module.project_id.length_range=項目ID長度必須在{min}-{max}之間
file_module.project_id.not_blank=項目ID不能為空
file_module.name.length_range=名稱長度必須在{min}-{max}之間
file_module.name.not_blank=名稱不能為空
file_repository.not.exist=存儲庫不存在
file_repository.connect.error=存储库链接失败
file_repository.platform.error=存儲庫類型不正確
file_repository.id.not_blank=存儲庫ID不能為空
file_repository.name.not_blank=存儲庫名稱不能為空
file_repository.type.not_blank=存儲庫類型不能為空
file_repository.token.not_blank=存儲庫token不能為空
file_repository.url.not_blank=存儲庫地址不能為空
file_repository.branch.not_blank=存儲庫分支不能為空
file_repository.file_path.not_blank=存儲庫文件路徑不能為空
custom_field_template.id.not_blank=ID不能為空
custom_field_template.field_id.length_range=字段ID長度必須在{min}-{max}之間
custom_field_template.field_id.not_blank=字段ID不能為空
@ -476,6 +478,7 @@ file.log.change_file_module=文件進行了移動
file.log.next=之後
file.log.previous=之前
file.log.upload=上傳
file.log.repository.add=添加了存儲庫文件
file.log.re-upload=重新上傳
file.name.cannot.be.empty=文件名稱不能為空
#file management over

View File

@ -3,6 +3,7 @@ package io.metersphere.project.controller;
import io.metersphere.project.dto.filemanagement.request.FileRepositoryConnectRequest;
import io.metersphere.project.dto.filemanagement.request.FileRepositoryCreateRequest;
import io.metersphere.project.dto.filemanagement.request.FileRepositoryUpdateRequest;
import io.metersphere.project.dto.filemanagement.request.RepositoryFileAddRequest;
import io.metersphere.project.service.FileMetadataService;
import io.metersphere.project.service.FileRepositoryService;
import io.metersphere.sdk.constants.PermissionConstants;
@ -59,8 +60,16 @@ public class FileRepositoryController {
}
@PostMapping("/connect")
@Operation(summary = "项目管理-文件管理-存储库-测试存储库链接")
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_ADD)
public void connect(@RequestBody @Validated FileRepositoryConnectRequest request) {
fileRepositoryService.connect(request.getUrl(), request.getToken(), request.getUserName());
}
@PostMapping("/add-file")
@Operation(summary = "项目管理-文件管理-存储库-添加文件")
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_ADD)
public String upload(@Validated @RequestBody RepositoryFileAddRequest request) throws Exception {
return fileRepositoryService.addFile(request, SessionUtils.getUserId());
}
}

View File

@ -0,0 +1,23 @@
package io.metersphere.project.dto.filemanagement.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class RepositoryFileAddRequest {
@Schema(description = "模块Id")
@NotBlank(message = "{file_module.id.not_blank}")
private String moduleId;
@Schema(description = "分支名")
@NotBlank(message = "{file_repository.branch.not_blank}")
private String branch;
@Schema(description = "文件路径")
@NotBlank(message = "{file_repository.file_path.not_blank}")
private String filePath;
@Schema(description = "开启/关闭(目前用于jar文件)")
private boolean enable;
}

View File

@ -1,8 +1,8 @@
package io.metersphere.project.service;
import io.metersphere.project.domain.FileMetadata;
import io.metersphere.project.domain.FileMetadataRepository;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.FileMetadataMapper;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.util.JSON;
@ -17,13 +17,16 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@Transactional(rollbackFor = Exception.class)
public class FileMetadataLogService {
@Resource
private FileMetadataMapper fileMetadataMapper;
private String logModule = OperationLogModule.PROJECT_FILE_MANAGEMENT;
@Resource
private ProjectMapper projectMapper;
@Resource
@ -35,7 +38,7 @@ public class FileMetadataLogService {
.projectId(module.getProjectId())
.organizationId(project.getOrganizationId())
.type(OperationLogType.ADD.name())
.module(OperationLogModule.PROJECT_FILE_MANAGEMENT)
.module(logModule)
.method(HttpMethodConstants.POST.name())
.path("/project/file/upload")
.sourceId(module.getId())
@ -52,7 +55,7 @@ public class FileMetadataLogService {
.projectId(module.getProjectId())
.organizationId(project.getOrganizationId())
.type(OperationLogType.UPDATE.name())
.module(OperationLogModule.PROJECT_FILE_MANAGEMENT)
.module(logModule)
.method(HttpMethodConstants.POST.name())
.path("/project/file/re-upload")
.sourceId(module.getId())
@ -69,7 +72,7 @@ public class FileMetadataLogService {
.projectId(projectId)
.organizationId(project.getOrganizationId())
.type(OperationLogType.UPDATE.name())
.module(OperationLogModule.PROJECT_FILE_MANAGEMENT)
.module(logModule)
.method(HttpMethodConstants.POST.name())
.path("/project/file/update")
.sourceId(module.getId())
@ -88,7 +91,7 @@ public class FileMetadataLogService {
.projectId(projectId)
.organizationId(project.getOrganizationId())
.type(OperationLogType.DELETE.name())
.module(OperationLogModule.PROJECT_FILE_MANAGEMENT)
.module(logModule)
.method(HttpMethodConstants.POST.name())
.path("/project/file/delete")
.sourceId(fileMetadata.getId())
@ -108,7 +111,7 @@ public class FileMetadataLogService {
.projectId(project.getId())
.organizationId(project.getOrganizationId())
.type(OperationLogType.UPDATE.name())
.module(OperationLogModule.PROJECT_FILE_MANAGEMENT)
.module(logModule)
.method(HttpMethodConstants.GET.name())
.path("/project/file/jar-file-status")
.sourceId(module.getId())
@ -127,7 +130,7 @@ public class FileMetadataLogService {
.projectId(projectId)
.organizationId(project.getOrganizationId())
.type(OperationLogType.UPDATE.name())
.module(OperationLogModule.PROJECT_FILE_MANAGEMENT)
.module(logModule)
.method(HttpMethodConstants.POST.name())
.path("/project/file/batch-move")
.sourceId(fileMetadata.getId())
@ -139,4 +142,25 @@ public class FileMetadataLogService {
operationLogService.batchAdd(list);
}
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);
}};
LogDTO dto = LogDTOBuilder.builder()
.projectId(fileMetadata.getProjectId())
.organizationId(project.getOrganizationId())
.type(OperationLogType.ADD.name())
.module(logModule)
.method(HttpMethodConstants.POST.name())
.path("/project/file/repository/add-file")
.sourceId(fileMetadata.getId())
.content(Translator.get("file.log.repository.add") + " " + fileMetadata.getName())
.originalValue(JSON.toJSONBytes(logContent))
.createUser(operator)
.build().getLogDTO();
operationLogService.add(dto);
}
}

View File

@ -106,43 +106,49 @@ public class FileMetadataService {
}
}
public String upload(FileUploadRequest request, String operator, MultipartFile uploadFile) throws Exception {
//检查模块的合法性
fileManagementService.checkModule(request.getModuleId(), ModuleConstants.NODE_TYPE_DEFAULT);
String fileName = StringUtils.trim(uploadFile.getOriginalFilename());
public FileMetadata saveFileMetadata(String projectId, String moduleId, String filePath, String operator, long size, boolean enable) {
String fileName = TempFileUtils.getFileNameByPath(filePath);
FileMetadata fileMetadata = new FileMetadata();
if (StringUtils.contains(fileName, ".")) {
if (StringUtils.lastIndexOf(fileName, ".") > 0) {
//采用这种判断方式可以避免将隐藏文件的后缀名作为文件类型
fileMetadata.setName(StringUtils.substring(fileName, 0, fileName.lastIndexOf(".")));
fileMetadata.setType(StringUtils.substring(fileName, fileName.lastIndexOf(".") + 1));
} else {
fileMetadata.setName(fileName);
fileMetadata.setType(StringUtils.EMPTY);
}
//检查处理后的用户名合法性
this.checkFileName(null, fileMetadata.getName(), request.getProjectId());
//如果开启了开关检查是否是jar文件
if (request.isEnable()) {
if (enable) {
this.checkEnableFile(fileMetadata.getType());
}
//检查处理后的用户名合法性
this.checkFileName(null, fileMetadata.getName(), projectId);
fileMetadata.setId(IDGenerator.nextStr());
fileMetadata.setStorage(StorageType.MINIO.name());
fileMetadata.setProjectId(request.getProjectId());
fileMetadata.setModuleId(request.getModuleId());
fileMetadata.setProjectId(projectId);
fileMetadata.setModuleId(moduleId);
long operationTime = System.currentTimeMillis();
fileMetadata.setCreateTime(operationTime);
fileMetadata.setCreateUser(operator);
fileMetadata.setUpdateTime(operationTime);
fileMetadata.setUpdateUser(operator);
fileMetadata.setSize(uploadFile.getSize());
fileMetadata.setSize(size);
fileMetadata.setPath(filePath);
fileMetadata.setLatest(true);
fileMetadata.setRefId(fileMetadata.getId());
fileMetadata.setEnable(false);
fileMetadataMapper.insert(fileMetadata);
return fileMetadata;
}
public String upload(FileUploadRequest request, String operator, MultipartFile uploadFile) throws Exception {
//检查模块的合法性
fileManagementService.checkModule(request.getModuleId(), ModuleConstants.NODE_TYPE_DEFAULT);
String fileName = StringUtils.trim(uploadFile.getOriginalFilename());
FileMetadata fileMetadata = this.saveFileMetadata(request.getProjectId(), request.getModuleId(), fileName, operator, uploadFile.getSize(), request.isEnable());
//记录日志
fileMetadataLogService.saveUploadLog(fileMetadata, operator);

View File

@ -1,16 +1,21 @@
package io.metersphere.project.service;
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.dto.filemanagement.FileRepositoryLog;
import io.metersphere.project.dto.filemanagement.request.FileRepositoryCreateRequest;
import io.metersphere.project.dto.filemanagement.request.FileRepositoryUpdateRequest;
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.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 jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
@ -25,8 +30,14 @@ import java.util.List;
@Transactional(rollbackFor = Exception.class)
public class FileRepositoryService extends FileModuleService {
@Resource
private FileMetadataLogService fileMetadataLogService;
@Resource
private FileMetadataService fileMetadataService;
@Resource
private FileModuleRepositoryMapper fileModuleRepositoryMapper;
@Resource
private FileMetadataRepositoryMapper fileMetadataRepositoryMapper;
public List<BaseTreeNode> getTree(String projectId) {
List<BaseTreeNode> fileModuleList = extFileModuleMapper.selectBaseByProjectId(projectId, ModuleConstants.NODE_TYPE_GIT);
@ -69,7 +80,7 @@ public class FileRepositoryService extends FileModuleService {
GitRepositoryUtil utils = new GitRepositoryUtil(url, userName, token);
List<String> branches = utils.getBranches();
if (CollectionUtils.isEmpty(branches)) {
throw new MSException(Translator.get("file_repository.not.exist"));
throw new MSException(Translator.get("file_repository.connect.error"));
}
}
@ -80,7 +91,7 @@ public class FileRepositoryService extends FileModuleService {
FileModule fileModule = fileModuleMapper.selectByPrimaryKey(request.getId());
FileModuleRepository repository = fileModuleRepositoryMapper.selectByPrimaryKey(request.getId());
if (ObjectUtils.anyNull(fileModule, repository)) {
throw new MSException(Translator.get("file_repository.not.exist"));
throw new MSException(Translator.get("file_repository.connect.error"));
}
this.connect(repository.getUrl(),
request.getToken() == null ? repository.getToken() : request.getToken(),
@ -111,4 +122,31 @@ public class FileRepositoryService extends FileModuleService {
throw new MSException(Translator.get("file_repository.platform.error"));
}
}
public String addFile(RepositoryFileAddRequest request, String operator) {
FileModule fileModule = fileModuleMapper.selectByPrimaryKey(request.getModuleId());
FileModuleRepository repository = fileModuleRepositoryMapper.selectByPrimaryKey(request.getModuleId());
if (ObjectUtils.anyNull(fileModule, repository)) {
throw new MSException(Translator.get("file_repository.connect.error"));
}
GitRepositoryUtil utils = new GitRepositoryUtil(repository.getUrl(), repository.getUserName(), repository.getToken());
RemoteFileAttachInfo fileAttachInfo = utils.selectLastCommitIdByBranch(request.getBranch(), request.getFilePath());
if (fileAttachInfo == null) {
throw new MSException(Translator.get("file.not.exist"));
}
FileMetadata fileMetadata = fileMetadataService.saveFileMetadata(
fileModule.getProjectId(), fileModule.getId(), request.getFilePath(), operator, fileAttachInfo.getSize(), request.isEnable());
FileMetadataRepository fileMetadataRepository = new FileMetadataRepository();
fileMetadataRepository.setFileMetadataId(fileMetadata.getId());
fileMetadataRepository.setBranch(fileAttachInfo.getBranch());
fileMetadataRepository.setCommitId(fileAttachInfo.getCommitId());
fileMetadataRepository.setCommitMessage(fileAttachInfo.getCommitMessage());
fileMetadataRepositoryMapper.insert(fileMetadataRepository);
//记录日志
fileMetadataLogService.saveRepositoryAddLog(fileMetadata, fileMetadataRepository, operator);
return fileMetadata.getId();
}
}

View File

@ -1,12 +1,23 @@
package io.metersphere.project.utils;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.dto.sdk.RemoteFileAttachInfo;
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.ArrayList;
import java.util.Collection;
@ -70,67 +81,67 @@ public class GitRepositoryUtil {
// return returnMap;
// }
// public RemoteFileAttachInfo selectLastCommitIdByBranch(String branch, String filePath) {
// RemoteFileAttachInfo attachInfo;
// InMemoryRepository repo = null;
// TreeWalk treeWalk = null;
// try {
// repo = this.getGitRepositoryInMemory(repositoryUrl, userName, token);
// ObjectId lastCommitId = repo.resolve("refs/heads/" + branch);
// if (lastCommitId != null) {
// RevCommit commit = this.getRevTreeByRepositoryAndCommitId(repo, lastCommitId);
// RevTree tree = commit.getTree();
// treeWalk = new TreeWalk(repo);
// treeWalk.addTree(tree);
// treeWalk.setRecursive(true);
// treeWalk.setFilter(PathFilter.create(filePath));
// if (!treeWalk.next()) {
// return null;
// } else {
// ObjectId objectId = treeWalk.getObjectId(0);
// ObjectLoader loader = repo.open(objectId);
// String fileLastCommitId = this.getFileLastCommitId(lastCommitId, filePath);
// if (StringUtils.isEmpty(fileLastCommitId)) {
// fileLastCommitId = lastCommitId.getName();
// }
// attachInfo = new RemoteFileAttachInfo(repositoryUrl, userName, token, branch, fileLastCommitId, filePath, commit.getFullMessage(), loader.getSize());
// return attachInfo;
// }
// }
// } catch (Exception e) {
// LogUtils.error("获取文件库文件报错!", e);
// } finally {
// if (treeWalk != null) {
// treeWalk.close();
// }
// this.closeConnection(repo);
// }
// return null;
// }
public RemoteFileAttachInfo selectLastCommitIdByBranch(String branch, String filePath) {
RemoteFileAttachInfo attachInfo;
InMemoryRepository repo = null;
TreeWalk treeWalk = null;
try {
repo = this.getGitRepositoryInMemory(repositoryUrl, userName, token);
ObjectId lastCommitId = repo.resolve("refs/heads/" + branch);
if (lastCommitId != null) {
RevCommit commit = this.getRevTreeByRepositoryAndCommitId(repo, lastCommitId);
RevTree tree = commit.getTree();
treeWalk = new TreeWalk(repo);
treeWalk.addTree(tree);
treeWalk.setRecursive(true);
treeWalk.setFilter(PathFilter.create(filePath));
if (!treeWalk.next()) {
return null;
} else {
ObjectId objectId = treeWalk.getObjectId(0);
ObjectLoader loader = repo.open(objectId);
String fileLastCommitId = this.getFileLastCommitId(lastCommitId, filePath);
if (StringUtils.isEmpty(fileLastCommitId)) {
fileLastCommitId = lastCommitId.getName();
}
attachInfo = new RemoteFileAttachInfo(repositoryUrl, userName, token, branch, fileLastCommitId, filePath, commit.getFullMessage(), loader.getSize());
return attachInfo;
}
}
} catch (Exception e) {
LogUtils.error("获取文件库文件报错!", e);
} finally {
if (treeWalk != null) {
treeWalk.close();
}
this.closeConnection(repo);
}
return null;
}
// private String getFileLastCommitId(ObjectId objectId, String filePath) throws Exception {
// Iterable<RevCommit> logs = git.log().add(objectId).addPath(filePath).call();
// String returnStr = StringUtils.EMPTY;
// for (RevCommit rev : logs) {
// returnStr = rev.getName();
// }
// return returnStr;
// }
private String getFileLastCommitId(ObjectId objectId, String filePath) throws Exception {
Iterable<RevCommit> logs = git.log().add(objectId).addPath(filePath).call();
String returnStr = StringUtils.EMPTY;
for (RevCommit rev : logs) {
returnStr = rev.getName();
}
return returnStr;
}
// private RevCommit getRevTreeByRepositoryAndCommitId(InMemoryRepository repo, ObjectId fileCommitId) throws IOException {
// RevWalk revWalk = new RevWalk(repo);
// return revWalk.parseCommit(fileCommitId);
// }
private RevCommit getRevTreeByRepositoryAndCommitId(InMemoryRepository repo, ObjectId fileCommitId) throws Exception {
RevWalk revWalk = new RevWalk(repo);
return revWalk.parseCommit(fileCommitId);
}
// 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 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 TreeWalk getTreeWork(InMemoryRepository repo, ObjectId fileCommitObjectId, String filePath) throws Exception {
// RevWalk revWalk = new RevWalk(repo);

View File

@ -1,13 +1,13 @@
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.dto.filemanagement.request.FileMetadataTableRequest;
import io.metersphere.project.dto.filemanagement.request.FileRepositoryConnectRequest;
import io.metersphere.project.dto.filemanagement.request.FileRepositoryCreateRequest;
import io.metersphere.project.dto.filemanagement.request.FileRepositoryUpdateRequest;
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;
@ -67,6 +67,8 @@ public class FileRepositoryControllerTest extends BaseTest {
@Resource
private FileModuleRepositoryMapper fileModuleRepositoryMapper;
@Resource
private FileMetadataRepositoryMapper fileMetadataRepositoryMapper;
@Resource
private FileMetadataMapper fileMetadataMapper;
@Resource
private CommonProjectService commonProjectService;
@ -315,6 +317,121 @@ public class FileRepositoryControllerTest extends BaseTest {
this.requestGetPermissionTest(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ, String.format(FileManagementRequestUtils.URL_FILE_REPOSITORY_LIST, DEFAULT_PROJECT_ID));
}
@Test
@Order(11)
public void repositoryAddFileTest() throws Exception {
if (StringUtils.isEmpty(repositoryId)) {
this.moduleAddTest();
}
//测试主分支的文件
String branch = "master";
String filePath = "README.en.md";
RepositoryFileAddRequest request = new RepositoryFileAddRequest();
request.setBranch(branch);
request.setFilePath(filePath);
request.setModuleId(repositoryId);
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);
//测试其他分支的多层目录的文件
String otherBranch = "develop";
String folderFilePath1 = "test-folder/gitee/test.txt";
request = new RepositoryFileAddRequest();
request.setBranch(otherBranch);
request.setFilePath(folderFilePath1);
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);
//测试隐藏文件
String folderFilePath2 = "test-folder/.keep";
request = new RepositoryFileAddRequest();
request.setBranch(otherBranch);
request.setFilePath(folderFilePath2);
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);
//测试添加jar包并且启用
request = new RepositoryFileAddRequest();
request.setBranch(branch);
request.setFilePath("jar-test/notJar.jar");
request.setEnable(true);
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);
{
//重复添加测试
request = new RepositoryFileAddRequest();
request.setBranch(otherBranch);
request.setFilePath(folderFilePath2);
request.setModuleId(repositoryId);
this.requestPost(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request).andExpect(status().is5xxServerError());
//测试添加非jar包并且启用
request = new RepositoryFileAddRequest();
request.setBranch(branch);
request.setFilePath("README.md");
request.setEnable(true);
request.setModuleId(repositoryId);
this.requestPost(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request).andExpect(status().is5xxServerError());
}
{
//测试不存在的文件
request = new RepositoryFileAddRequest();
request.setBranch(otherBranch);
request.setFilePath(IDGenerator.nextStr());
request.setModuleId(repositoryId);
this.requestPost(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request).andExpect(status().is5xxServerError());
//测试不存在的分支
request = new RepositoryFileAddRequest();
request.setBranch(IDGenerator.nextStr());
request.setFilePath(folderFilePath2);
request.setModuleId(repositoryId);
this.requestPost(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request).andExpect(status().is5xxServerError());
//不存在的moduleId
request = new RepositoryFileAddRequest();
request.setBranch(otherBranch);
request.setFilePath(folderFilePath2);
request.setModuleId(IDGenerator.nextStr());
this.requestPost(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request).andExpect(status().is5xxServerError());
}
{
//参数测试
request = new RepositoryFileAddRequest();
request.setFilePath(folderFilePath2);
request.setModuleId(repositoryId);
this.requestPost(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request).andExpect(status().isBadRequest());
request = new RepositoryFileAddRequest();
request.setBranch(IDGenerator.nextStr());
request.setModuleId(repositoryId);
this.requestPost(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request).andExpect(status().isBadRequest());
request = new RepositoryFileAddRequest();
request.setBranch(IDGenerator.nextStr());
request.setFilePath(folderFilePath2);
this.requestPost(FileManagementRequestUtils.URL_FILE_REPOSITORY_FILE_ADD, request).andExpect(status().isBadRequest());
}
}
private void checkFileRepositoryFile(String fileId, RepositoryFileAddRequest request) {
FileMetadataRepository repository = fileMetadataRepositoryMapper.selectByPrimaryKey(fileId);
Assertions.assertEquals(repository.getBranch(), request.getBranch());
Assertions.assertNotNull(repository.getCommitId());
Assertions.assertNotNull(repository.getCommitMessage());
FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId);
Assertions.assertEquals(fileMetadata.getPath(), request.getFilePath());
}
@Test
@Order(20)
public void repositoryFileTypeTest() throws Exception {

View File

@ -55,4 +55,7 @@ public class FileManagementRequestUtils {
//修改存储库
public static final String URL_FILE_REPOSITORY_UPDATE = "/project/file/repository/update-repository";
//添加文件
public static final String URL_FILE_REPOSITORY_FILE_ADD = "/project/file/repository/add-file";
}

View File

@ -20,8 +20,4 @@ public class RemoteFileAttachInfo implements Serializable {
private String filePath;
private String commitMessage;
private long size;
public String getRepositoryInfo() {
return repositoryPath + "-" + userName + "-" + token;
}
}