feat(项目管理): 文件关联功能开发
This commit is contained in:
parent
5c47422999
commit
9e5285faa1
|
@ -15,11 +15,6 @@ public class FileAssociation implements Serializable {
|
|||
@Size(min = 1, max = 50, message = "{file_association.id.length_range}", groups = {Created.class, Updated.class})
|
||||
private String id;
|
||||
|
||||
@Schema(description = "多用于场景步骤内具体的步骤ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{file_association.source_item_id.not_blank}", groups = {Created.class})
|
||||
@Size(min = 1, max = 50, message = "{file_association.source_item_id.length_range}", groups = {Created.class, Updated.class})
|
||||
private String sourceItemId;
|
||||
|
||||
@Schema(description = "资源类型", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{file_association.source_type.not_blank}", groups = {Created.class})
|
||||
@Size(min = 1, max = 50, message = "{file_association.source_type.length_range}", groups = {Created.class, Updated.class})
|
||||
|
@ -61,7 +56,6 @@ public class FileAssociation implements Serializable {
|
|||
|
||||
public enum Column {
|
||||
id("id", "id", "VARCHAR", false),
|
||||
sourceItemId("source_item_id", "sourceItemId", "VARCHAR", false),
|
||||
sourceType("source_type", "sourceType", "VARCHAR", false),
|
||||
sourceId("source_id", "sourceId", "VARCHAR", false),
|
||||
fileId("file_id", "fileId", "VARCHAR", false),
|
||||
|
|
|
@ -174,76 +174,6 @@ public class FileAssociationExample {
|
|||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdIsNull() {
|
||||
addCriterion("source_item_id is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdIsNotNull() {
|
||||
addCriterion("source_item_id is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdEqualTo(String value) {
|
||||
addCriterion("source_item_id =", value, "sourceItemId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdNotEqualTo(String value) {
|
||||
addCriterion("source_item_id <>", value, "sourceItemId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdGreaterThan(String value) {
|
||||
addCriterion("source_item_id >", value, "sourceItemId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("source_item_id >=", value, "sourceItemId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdLessThan(String value) {
|
||||
addCriterion("source_item_id <", value, "sourceItemId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdLessThanOrEqualTo(String value) {
|
||||
addCriterion("source_item_id <=", value, "sourceItemId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdLike(String value) {
|
||||
addCriterion("source_item_id like", value, "sourceItemId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdNotLike(String value) {
|
||||
addCriterion("source_item_id not like", value, "sourceItemId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdIn(List<String> values) {
|
||||
addCriterion("source_item_id in", values, "sourceItemId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdNotIn(List<String> values) {
|
||||
addCriterion("source_item_id not in", values, "sourceItemId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdBetween(String value1, String value2) {
|
||||
addCriterion("source_item_id between", value1, value2, "sourceItemId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceItemIdNotBetween(String value1, String value2) {
|
||||
addCriterion("source_item_id not between", value1, value2, "sourceItemId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceTypeIsNull() {
|
||||
addCriterion("source_type is null");
|
||||
return (Criteria) this;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
<mapper namespace="io.metersphere.project.mapper.FileAssociationMapper">
|
||||
<resultMap id="BaseResultMap" type="io.metersphere.project.domain.FileAssociation">
|
||||
<id column="id" jdbcType="VARCHAR" property="id" />
|
||||
<result column="source_item_id" jdbcType="VARCHAR" property="sourceItemId" />
|
||||
<result column="source_type" jdbcType="VARCHAR" property="sourceType" />
|
||||
<result column="source_id" jdbcType="VARCHAR" property="sourceId" />
|
||||
<result column="file_id" jdbcType="VARCHAR" property="fileId" />
|
||||
|
@ -73,8 +72,8 @@
|
|||
</where>
|
||||
</sql>
|
||||
<sql id="Base_Column_List">
|
||||
id, source_item_id, source_type, source_id, file_id, file_ref_id, file_version, create_time,
|
||||
update_user, update_time, create_user
|
||||
id, source_type, source_id, file_id, file_ref_id, file_version, create_time, update_user,
|
||||
update_time, create_user
|
||||
</sql>
|
||||
<select id="selectByExample" parameterType="io.metersphere.project.domain.FileAssociationExample" resultMap="BaseResultMap">
|
||||
select
|
||||
|
@ -107,14 +106,14 @@
|
|||
</if>
|
||||
</delete>
|
||||
<insert id="insert" parameterType="io.metersphere.project.domain.FileAssociation">
|
||||
insert into file_association (id, source_item_id, source_type,
|
||||
source_id, file_id, file_ref_id,
|
||||
file_version, create_time, update_user,
|
||||
update_time, create_user)
|
||||
values (#{id,jdbcType=VARCHAR}, #{sourceItemId,jdbcType=VARCHAR}, #{sourceType,jdbcType=VARCHAR},
|
||||
#{sourceId,jdbcType=VARCHAR}, #{fileId,jdbcType=VARCHAR}, #{fileRefId,jdbcType=VARCHAR},
|
||||
#{fileVersion,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateUser,jdbcType=VARCHAR},
|
||||
#{updateTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR})
|
||||
insert into file_association (id, source_type, source_id,
|
||||
file_id, file_ref_id, file_version,
|
||||
create_time, update_user, update_time,
|
||||
create_user)
|
||||
values (#{id,jdbcType=VARCHAR}, #{sourceType,jdbcType=VARCHAR}, #{sourceId,jdbcType=VARCHAR},
|
||||
#{fileId,jdbcType=VARCHAR}, #{fileRefId,jdbcType=VARCHAR}, #{fileVersion,jdbcType=VARCHAR},
|
||||
#{createTime,jdbcType=BIGINT}, #{updateUser,jdbcType=VARCHAR}, #{updateTime,jdbcType=BIGINT},
|
||||
#{createUser,jdbcType=VARCHAR})
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="io.metersphere.project.domain.FileAssociation">
|
||||
insert into file_association
|
||||
|
@ -122,9 +121,6 @@
|
|||
<if test="id != null">
|
||||
id,
|
||||
</if>
|
||||
<if test="sourceItemId != null">
|
||||
source_item_id,
|
||||
</if>
|
||||
<if test="sourceType != null">
|
||||
source_type,
|
||||
</if>
|
||||
|
@ -157,9 +153,6 @@
|
|||
<if test="id != null">
|
||||
#{id,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="sourceItemId != null">
|
||||
#{sourceItemId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="sourceType != null">
|
||||
#{sourceType,jdbcType=VARCHAR},
|
||||
</if>
|
||||
|
@ -201,9 +194,6 @@
|
|||
<if test="record.id != null">
|
||||
id = #{record.id,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.sourceItemId != null">
|
||||
source_item_id = #{record.sourceItemId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.sourceType != null">
|
||||
source_type = #{record.sourceType,jdbcType=VARCHAR},
|
||||
</if>
|
||||
|
@ -239,7 +229,6 @@
|
|||
<update id="updateByExample" parameterType="map">
|
||||
update file_association
|
||||
set id = #{record.id,jdbcType=VARCHAR},
|
||||
source_item_id = #{record.sourceItemId,jdbcType=VARCHAR},
|
||||
source_type = #{record.sourceType,jdbcType=VARCHAR},
|
||||
source_id = #{record.sourceId,jdbcType=VARCHAR},
|
||||
file_id = #{record.fileId,jdbcType=VARCHAR},
|
||||
|
@ -256,9 +245,6 @@
|
|||
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.project.domain.FileAssociation">
|
||||
update file_association
|
||||
<set>
|
||||
<if test="sourceItemId != null">
|
||||
source_item_id = #{sourceItemId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="sourceType != null">
|
||||
source_type = #{sourceType,jdbcType=VARCHAR},
|
||||
</if>
|
||||
|
@ -291,8 +277,7 @@
|
|||
</update>
|
||||
<update id="updateByPrimaryKey" parameterType="io.metersphere.project.domain.FileAssociation">
|
||||
update file_association
|
||||
set source_item_id = #{sourceItemId,jdbcType=VARCHAR},
|
||||
source_type = #{sourceType,jdbcType=VARCHAR},
|
||||
set source_type = #{sourceType,jdbcType=VARCHAR},
|
||||
source_id = #{sourceId,jdbcType=VARCHAR},
|
||||
file_id = #{fileId,jdbcType=VARCHAR},
|
||||
file_ref_id = #{fileRefId,jdbcType=VARCHAR},
|
||||
|
@ -305,14 +290,14 @@
|
|||
</update>
|
||||
<insert id="batchInsert" parameterType="map">
|
||||
insert into file_association
|
||||
(id, source_item_id, source_type, source_id, file_id, file_ref_id, file_version,
|
||||
create_time, update_user, update_time, create_user)
|
||||
(id, source_type, source_id, file_id, file_ref_id, file_version, create_time, update_user,
|
||||
update_time, create_user)
|
||||
values
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.id,jdbcType=VARCHAR}, #{item.sourceItemId,jdbcType=VARCHAR}, #{item.sourceType,jdbcType=VARCHAR},
|
||||
#{item.sourceId,jdbcType=VARCHAR}, #{item.fileId,jdbcType=VARCHAR}, #{item.fileRefId,jdbcType=VARCHAR},
|
||||
#{item.fileVersion,jdbcType=VARCHAR}, #{item.createTime,jdbcType=BIGINT}, #{item.updateUser,jdbcType=VARCHAR},
|
||||
#{item.updateTime,jdbcType=BIGINT}, #{item.createUser,jdbcType=VARCHAR})
|
||||
(#{item.id,jdbcType=VARCHAR}, #{item.sourceType,jdbcType=VARCHAR}, #{item.sourceId,jdbcType=VARCHAR},
|
||||
#{item.fileId,jdbcType=VARCHAR}, #{item.fileRefId,jdbcType=VARCHAR}, #{item.fileVersion,jdbcType=VARCHAR},
|
||||
#{item.createTime,jdbcType=BIGINT}, #{item.updateUser,jdbcType=VARCHAR}, #{item.updateTime,jdbcType=BIGINT},
|
||||
#{item.createUser,jdbcType=VARCHAR})
|
||||
</foreach>
|
||||
</insert>
|
||||
<insert id="batchInsertSelective" parameterType="map">
|
||||
|
@ -328,9 +313,6 @@
|
|||
<if test="'id'.toString() == column.value">
|
||||
#{item.id,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="'source_item_id'.toString() == column.value">
|
||||
#{item.sourceItemId,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="'source_type'.toString() == column.value">
|
||||
#{item.sourceType,jdbcType=VARCHAR}
|
||||
</if>
|
||||
|
|
|
@ -46,7 +46,6 @@ CREATE INDEX idx_name ON fake_error (name);
|
|||
CREATE TABLE IF NOT EXISTS file_association
|
||||
(
|
||||
`id` VARCHAR(50) NOT NULL COMMENT '',
|
||||
`source_item_id` VARCHAR(50) NOT NULL COMMENT '多用于场景步骤内具体的步骤ID',
|
||||
`source_type` VARCHAR(50) NOT NULL COMMENT '资源类型',
|
||||
`source_id` VARCHAR(50) NOT NULL COMMENT '资源ID',
|
||||
`file_id` VARCHAR(50) NOT NULL COMMENT '文件ID',
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package io.metersphere.sdk.util;
|
||||
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文件关联资源类型
|
||||
* 注:类型如果要拓展,QUERY_SQL 中要增加对应的数据库名称查询SQL (不需要拼接where条件)
|
||||
*/
|
||||
public class FileAssociationSourceUtil {
|
||||
public static final String SOURCE_TYPE_BUG = "BUG";
|
||||
public static final Map<String, String> QUERY_SQL = new HashMap<>();
|
||||
|
||||
static {
|
||||
QUERY_SQL.put(SOURCE_TYPE_BUG, "SELECT id AS sourceId,title AS sourceName FROM bug");
|
||||
}
|
||||
|
||||
public static void validate(String type) {
|
||||
if (!QUERY_SQL.containsKey(type)) {
|
||||
throw new MSException(Translator.get("file.association.error.type"));
|
||||
}
|
||||
}
|
||||
public static String getQuerySql(String type) {
|
||||
validate(type);
|
||||
return QUERY_SQL.get(type) + StringUtils.SPACE;
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ 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.connect.error=存储库链接失败
|
||||
file_repository.connect.error=存储库连接失败
|
||||
file_repository.not.exist=存储库不存在
|
||||
file_repository.platform.error=存储库类型不正确
|
||||
file_repository.id.not_blank=存储库ID不能为空
|
||||
|
@ -30,6 +30,7 @@ file_repository.url.not_blank=存储库地址不能为空
|
|||
file_repository.branch.not_blank=存储库分支不能为空
|
||||
file_repository.file_path.not_blank=存储库文件路径不能为空
|
||||
file.association.error.type=不支持的文件关联资源类型
|
||||
file.association.not.exist=文件并未关联
|
||||
file.association.source.not.exist=文件关联时资源不存在
|
||||
custom_field_template.id.not_blank=ID不能为空
|
||||
custom_field_template.field_id.length_range=字段ID长度必须在{min}-{max}之间
|
||||
|
@ -436,6 +437,7 @@ upload.file.error=上传文件失败
|
|||
file.not.exist=文件不存在
|
||||
file.some.not.exist=部分文件不存在
|
||||
old.file.not.exist=旧文件不存在
|
||||
latest.file.not.exist=最新文件不存在
|
||||
file.not.jar=不是jar文件
|
||||
change.jar.enable=修改了jar文件的启用状态
|
||||
file.name.exist=文件名已存在
|
||||
|
@ -449,7 +451,12 @@ file.log.upload=上传
|
|||
file.log.repository.add=添加了存储库文件
|
||||
file.log.re-upload=重新上传
|
||||
file.log.pull=拉取了文件
|
||||
file.log.association=关联了文件
|
||||
file.log.association.update=更新了关联了文件
|
||||
file.log.association.delete=取消关联了文件
|
||||
file.log.transfer.association=转存并关联了文件
|
||||
file.name.cannot.be.empty=文件名称不能为空
|
||||
file.name.error=文件名不合法
|
||||
#file management over
|
||||
|
||||
# template
|
||||
|
|
|
@ -32,6 +32,7 @@ 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.association.error.type=Source type is error
|
||||
file.association.not.exist=File not association
|
||||
file.association.source.not.exist=Source not exist
|
||||
file_repository.connect.error=Repository connect error
|
||||
file_repository.not.exist=Repository not exist
|
||||
|
@ -472,6 +473,7 @@ upload.file.error=Upload file error
|
|||
file.not.exist=File does not exist
|
||||
file.some.not.exist=Some file not exist
|
||||
old.file.not.exist=Old file does not exist
|
||||
latest.file.not.exist=New version file note exist
|
||||
file.not.jar=Not jar file
|
||||
change.jar.enable=Change jar file enable
|
||||
file.name.exist=File name already exists
|
||||
|
@ -485,7 +487,12 @@ file.log.upload=upload
|
|||
file.log.repository.add=Add repository file
|
||||
file.log.re-upload=re-upload
|
||||
file.log.pull=Pull file
|
||||
file.log.association=has association file
|
||||
file.log.association.update=updated file
|
||||
file.log.association.delete=delete file
|
||||
file.log.transfer.association=transfer and association file
|
||||
file.name.cannot.be.empty=File name cannot be empty
|
||||
file.name.error=File name error
|
||||
#file management over
|
||||
|
||||
# template
|
||||
|
|
|
@ -32,8 +32,9 @@ file_module.project_id.not_blank=项目ID不能为空
|
|||
file_module.name.length_range=名称长度必须在{min}-{max}之间
|
||||
file_module.name.not_blank=名称不能为空
|
||||
file.association.error.type=不支持的文件关联资源类型
|
||||
file.association.not.exist=文件并未关联
|
||||
file.association.source.not.exist=文件关联时资源不存在
|
||||
file_repository.connect.error=存储库链接失败
|
||||
file_repository.connect.error=存储库连接失败
|
||||
file_repository.not.exist=存储库不存在
|
||||
file_repository.platform.error=存储库类型不正确
|
||||
file_repository.id.not_blank=存储库ID不能为空
|
||||
|
@ -471,6 +472,7 @@ upload.file.error=上传文件失败
|
|||
file.not.exist=文件不存在
|
||||
file.some.not.exist=部分文件不存在
|
||||
old.file.not.exist=旧文件不存在
|
||||
latest.file.not.exist=最新文件不存在
|
||||
file.not.jar=不是jar文件
|
||||
change.jar.enable=修改了jar文件的启用状态
|
||||
file.name.exist=文件名已存在
|
||||
|
@ -484,7 +486,12 @@ file.log.upload=上传
|
|||
file.log.repository.add=添加了存储库文件
|
||||
file.log.re-upload=重新上传
|
||||
file.log.pull=拉取了文件
|
||||
file.log.association=关联了文件
|
||||
file.log.association.update=更新了关联了文件
|
||||
file.log.association.delete=取消关联了文件
|
||||
file.log.transfer.association=转存并关联了文件
|
||||
file.name.cannot.be.empty=文件名称不能为空
|
||||
file.name.error=文件名不合法
|
||||
#file management over
|
||||
# template
|
||||
project_template_permission_error=未开启项目模板
|
||||
|
|
|
@ -32,8 +32,9 @@ file_module.project_id.not_blank=項目ID不能為空
|
|||
file_module.name.length_range=名稱長度必須在{min}-{max}之間
|
||||
file_module.name.not_blank=名稱不能為空
|
||||
file.association.error.type=不支持的文件關聯資源類型
|
||||
file.association.not.exist=文件並未關聯
|
||||
file.association.source.not.exist=文件關聯時資源不存在
|
||||
file_repository.connect.error=存儲庫鏈接失敗
|
||||
file_repository.connect.error=存儲庫連接失敗
|
||||
file_repository.not.exist=存儲庫不存在
|
||||
file_repository.platform.error=存儲庫類型不正確
|
||||
file_repository.id.not_blank=存儲庫ID不能為空
|
||||
|
@ -472,6 +473,7 @@ upload.file.error=上傳文件失敗
|
|||
file.not.exist=文件不存在
|
||||
file.some.not.exist=部分文件不存在
|
||||
old.file.not.exist=舊文件不存在
|
||||
latest.file.not.exist=最新文件不存在
|
||||
file.not.jar=不是jar文件
|
||||
change.jar.enable=修改了jar文件的啟用狀態
|
||||
file.name.exist=文件名已存在
|
||||
|
@ -485,7 +487,12 @@ file.log.upload=上傳
|
|||
file.log.repository.add=添加了存儲庫文件
|
||||
file.log.re-upload=重新上傳
|
||||
file.log.pull=拉取了文件
|
||||
file.log.association=關聯了文件
|
||||
file.log.association.update=更新了關聯了文件
|
||||
file.log.association.delete=取消關聯了文件
|
||||
file.log.transfer.association=轉存並關聯了文件
|
||||
file.name.cannot.be.empty=文件名稱不能為空
|
||||
file.name.error=文件名不合法
|
||||
#file management over
|
||||
|
||||
# template
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package io.metersphere.project.controller;
|
||||
|
||||
import io.metersphere.project.dto.filemanagement.FileLogRecord;
|
||||
import io.metersphere.project.dto.filemanagement.request.FileAssociationDeleteRequest;
|
||||
import io.metersphere.project.dto.filemanagement.response.FileAssociationResponse;
|
||||
import io.metersphere.project.service.FileAssociationService;
|
||||
import io.metersphere.sdk.constants.HttpMethodConstants;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
import io.metersphere.system.log.constants.OperationLogModule;
|
||||
import io.metersphere.system.utils.SessionUtils;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Tag(name = "项目管理-文件管理-文件关联")
|
||||
@RestController
|
||||
@RequestMapping("/project/file/association")
|
||||
public class FileAssociationController {
|
||||
|
||||
@Resource
|
||||
private FileAssociationService fileAssociationService;
|
||||
|
||||
@GetMapping("/list/{id}")
|
||||
@Operation(summary = "项目管理-文件管理-表格分页查询文件")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ)
|
||||
public List<FileAssociationResponse> getAssociationList(@PathVariable String id) {
|
||||
return fileAssociationService.selectFileAllVersionAssociation(id);
|
||||
}
|
||||
|
||||
@GetMapping("/upgrade/{projectId}/{id}")
|
||||
@Operation(summary = "项目管理-文件管理-表格分页查询文件")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_UPDATE)
|
||||
public String upgrade(@PathVariable String projectId,@PathVariable String id) {
|
||||
FileLogRecord fileLogRecord = FileLogRecord.builder()
|
||||
.logModule(OperationLogModule.PROJECT_FILE_MANAGEMENT)
|
||||
.requestMethod(HttpMethodConstants.GET.name())
|
||||
.requestUrl("/project/file/association/upgrade/{projectId}/{id}")
|
||||
.operator(SessionUtils.getUserId())
|
||||
.projectId(projectId)
|
||||
.build();
|
||||
|
||||
return fileAssociationService.upgrade(id,fileLogRecord);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
@Operation(summary = "项目管理-文件管理-表格分页查询文件")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_UPDATE)
|
||||
public int delete(@RequestBody @Validated FileAssociationDeleteRequest request) {
|
||||
FileLogRecord fileLogRecord = FileLogRecord.builder()
|
||||
.logModule(OperationLogModule.PROJECT_FILE_MANAGEMENT)
|
||||
.requestMethod(HttpMethodConstants.POST.name())
|
||||
.requestUrl("/project/file/association/delete")
|
||||
.operator(SessionUtils.getUserId())
|
||||
.projectId(request.getProjectId())
|
||||
.build();
|
||||
|
||||
return fileAssociationService.deleteBySourceId(request.getAssociationIds(),fileLogRecord);
|
||||
}
|
||||
}
|
|
@ -48,7 +48,7 @@ public class FileManagementController {
|
|||
@Operation(summary = "项目管理-文件管理-查看文件详情")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ)
|
||||
public FileInformationResponse page(@PathVariable String id) {
|
||||
return fileMetadataService.get(id);
|
||||
return fileMetadataService.getFileInformation(id);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ public class FilePreviewController {
|
|||
@GetMapping(value = "/original/{userId}/{fileId}")
|
||||
@Operation(summary = "预览原图")
|
||||
public ResponseEntity<byte[]> originalImg(@PathVariable String userId, @PathVariable String fileId) throws Exception {
|
||||
FileInformationResponse fileInformationResponse = fileMetadataService.get(fileId);
|
||||
FileInformationResponse fileInformationResponse = fileMetadataService.getFileInformation(fileId);
|
||||
if (StringUtils.isEmpty(fileInformationResponse.getId())) {
|
||||
throw new MSException("file.not.exist");
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ public class FilePreviewController {
|
|||
@GetMapping(value = "/compressed/{userId}/{fileId}")
|
||||
@Operation(summary = "预览缩略图")
|
||||
public ResponseEntity<byte[]> compressedImg(@PathVariable String userId, @PathVariable String fileId) throws Exception {
|
||||
FileInformationResponse fileInformationResponse = fileMetadataService.get(fileId);
|
||||
FileInformationResponse fileInformationResponse = fileMetadataService.getFileInformation(fileId);
|
||||
if (StringUtils.isEmpty(fileInformationResponse.getId())) {
|
||||
throw new MSException("file.not.exist");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package io.metersphere.project.dto.filemanagement;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FileAssociationSource {
|
||||
private String sourceId;
|
||||
private String sourceName;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package io.metersphere.project.dto.filemanagement;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class FileLogRecord {
|
||||
//操作人
|
||||
@NotBlank
|
||||
private String operator;
|
||||
//请求方法 POST/GET
|
||||
@NotBlank
|
||||
private String requestMethod;
|
||||
//触发log记录的请求路径
|
||||
@NotBlank
|
||||
private String requestUrl;
|
||||
//log所属记录模块
|
||||
@NotBlank
|
||||
private String logModule;
|
||||
//log所属项目ID
|
||||
@NotBlank
|
||||
private String projectId;
|
||||
}
|
|
@ -3,8 +3,10 @@ package io.metersphere.project.dto.filemanagement;
|
|||
import io.metersphere.project.domain.FileModule;
|
||||
import io.metersphere.project.domain.FileModuleRepository;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class FileRepositoryLog {
|
||||
private String id;
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package io.metersphere.project.dto.filemanagement.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class FileAssociationDeleteRequest {
|
||||
@Schema(description = "要删除的id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "{file.association.source.not.exist}")
|
||||
List<@Valid @NotBlank(message = "{file.association.source.not.exist}") String> associationIds;
|
||||
|
||||
@Schema(description = "项目Id")
|
||||
@NotBlank(message = "{project.id.not_blank}")
|
||||
private String projectId;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package io.metersphere.project.dto.filemanagement.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class FileAssociationResponse {
|
||||
@Schema(description = "ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "资源Id")
|
||||
private String sourceId;
|
||||
|
||||
@Schema(description = "文件Id")
|
||||
private String fileId;
|
||||
|
||||
@Schema(description = "资源名称")
|
||||
private String sourceName;
|
||||
|
||||
@Schema(description = "资源类型")
|
||||
private String sourceType;
|
||||
|
||||
@Schema(description = "文件版本")
|
||||
private String fileVersion;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package io.metersphere.project.mapper;
|
||||
|
||||
import io.metersphere.project.dto.filemanagement.FileAssociationSource;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 注:本类中所有带有querySql参数的方法,不能直接传入sql,
|
||||
* 要使用FileAssociationResourceUtil.getQuerySql(sourceType)。防止SQL注入
|
||||
*/
|
||||
public interface ExtFileAssociationMapper {
|
||||
FileAssociationSource selectNameBySourceTableAndId(@Param("querySql") String querySql, @Param("sourceId") String sourceId);
|
||||
List<FileAssociationSource> selectAssociationSourceBySourceTableAndIdList(@Param("querySql") String querySql, @Param("idList") List<String> sourceIdList);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?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.project.mapper.ExtFileAssociationMapper">
|
||||
<select id="selectNameBySourceTableAndId"
|
||||
resultType="io.metersphere.project.dto.filemanagement.FileAssociationSource">
|
||||
${querySql}
|
||||
WHERE id = #{sourceId}
|
||||
</select>
|
||||
<select id="selectAssociationSourceBySourceTableAndIdList"
|
||||
resultType="io.metersphere.project.dto.filemanagement.FileAssociationSource">
|
||||
${querySql}
|
||||
WHERE id IN
|
||||
<foreach collection="idList" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
</mapper>
|
|
@ -0,0 +1,121 @@
|
|||
package io.metersphere.project.service;
|
||||
|
||||
import io.metersphere.project.domain.FileMetadata;
|
||||
import io.metersphere.project.domain.Project;
|
||||
import io.metersphere.project.dto.filemanagement.FileLogRecord;
|
||||
import io.metersphere.project.mapper.ProjectMapper;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.dto.builder.LogDTOBuilder;
|
||||
import io.metersphere.system.log.constants.OperationLogType;
|
||||
import io.metersphere.system.log.dto.LogDTO;
|
||||
import io.metersphere.system.log.service.OperationLogService;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class FileAssociationLogService {
|
||||
|
||||
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
@Resource
|
||||
private OperationLogService operationLogService;
|
||||
|
||||
public void saveBatchInsertLog(String sourceName, List<FileMetadata> addFileList, FileLogRecord fileLogRecord) {
|
||||
List<LogDTO> list = new ArrayList<>();
|
||||
Project project = projectMapper.selectByPrimaryKey(fileLogRecord.getProjectId());
|
||||
for (FileMetadata fileMetadata : addFileList) {
|
||||
LogDTO dto = LogDTOBuilder.builder()
|
||||
.projectId(project.getId())
|
||||
.organizationId(project.getOrganizationId())
|
||||
.type(OperationLogType.ADD.name())
|
||||
.module(fileLogRecord.getLogModule())
|
||||
.method(fileLogRecord.getRequestMethod())
|
||||
.path(fileLogRecord.getRequestUrl())
|
||||
.createUser(fileLogRecord.getOperator())
|
||||
.sourceId(fileMetadata.getId())
|
||||
.content(sourceName + StringUtils.SPACE + Translator.get("file.log.association") + ":" + fileMetadata.getName())
|
||||
.build().getLogDTO();
|
||||
list.add(dto);
|
||||
}
|
||||
operationLogService.batchAdd(list);
|
||||
}
|
||||
|
||||
public void saveBatchUpdateLog(String sourceName, Collection<FileMetadata> values, FileLogRecord fileLogRecord) {
|
||||
List<LogDTO> list = new ArrayList<>();
|
||||
Project project = projectMapper.selectByPrimaryKey(fileLogRecord.getProjectId());
|
||||
for (FileMetadata fileMetadata : values) {
|
||||
LogDTO dto = this.genUpdateFileAssociationLogDTO(project, sourceName, fileMetadata, fileLogRecord);
|
||||
list.add(dto);
|
||||
}
|
||||
operationLogService.batchAdd(list);
|
||||
}
|
||||
|
||||
public void saveUpdateLog(String sourceName, FileMetadata fileMetadata, FileLogRecord fileLogRecord) {
|
||||
Project project = projectMapper.selectByPrimaryKey(fileLogRecord.getProjectId());
|
||||
LogDTO dto = this.genUpdateFileAssociationLogDTO(project, sourceName, fileMetadata, fileLogRecord);
|
||||
operationLogService.add(dto);
|
||||
}
|
||||
|
||||
private LogDTO genUpdateFileAssociationLogDTO(Project project, String sourceName, FileMetadata fileMetadata, FileLogRecord fileLogRecord) {
|
||||
return LogDTOBuilder.builder()
|
||||
.projectId(project.getId())
|
||||
.organizationId(project.getOrganizationId())
|
||||
.type(OperationLogType.UPDATE.name())
|
||||
.module(fileLogRecord.getLogModule())
|
||||
.method(fileLogRecord.getRequestMethod())
|
||||
.path(fileLogRecord.getRequestUrl())
|
||||
.createUser(fileLogRecord.getOperator())
|
||||
.sourceId(fileMetadata.getId())
|
||||
.content(sourceName + StringUtils.SPACE + Translator.get("file.log.association.update") + ":" + fileMetadata.getName())
|
||||
.build().getLogDTO();
|
||||
}
|
||||
|
||||
public void saveDeleteLog(Map<String, List<String>> sourceToFileNameMap, FileLogRecord fileLogRecord) {
|
||||
Project project = projectMapper.selectByPrimaryKey(fileLogRecord.getProjectId());
|
||||
List<LogDTO> list = new ArrayList<>();
|
||||
for (Map.Entry<String, List<String>> entry : sourceToFileNameMap.entrySet()) {
|
||||
String sourceName = entry.getKey();
|
||||
List<String> fileNameList = entry.getValue();
|
||||
LogDTO dto = LogDTOBuilder.builder()
|
||||
.projectId(project.getId())
|
||||
.organizationId(project.getOrganizationId())
|
||||
.type(OperationLogType.DELETE.name())
|
||||
.module(fileLogRecord.getLogModule())
|
||||
.method(fileLogRecord.getRequestMethod())
|
||||
.path(fileLogRecord.getRequestUrl())
|
||||
.createUser(fileLogRecord.getOperator())
|
||||
.sourceId(IDGenerator.nextStr())
|
||||
.content(sourceName + StringUtils.SPACE + Translator.get("file.log.association.delete") + ":" + StringUtils.join(fileNameList, ","))
|
||||
.build().getLogDTO();
|
||||
list.add(dto);
|
||||
}
|
||||
operationLogService.batchAdd(list);
|
||||
}
|
||||
|
||||
public void saveTransferAssociationLog(String sourceId, String fileName, String sourceName, FileLogRecord fileLogRecord) {
|
||||
Project project = projectMapper.selectByPrimaryKey(fileLogRecord.getProjectId());
|
||||
LogDTO dto = LogDTOBuilder.builder()
|
||||
.projectId(project.getId())
|
||||
.organizationId(project.getOrganizationId())
|
||||
.type(OperationLogType.ADD.name())
|
||||
.module(fileLogRecord.getLogModule())
|
||||
.method(fileLogRecord.getRequestMethod())
|
||||
.path(fileLogRecord.getRequestUrl())
|
||||
.createUser(fileLogRecord.getOperator())
|
||||
.sourceId(sourceId)
|
||||
.content(sourceName + StringUtils.SPACE + Translator.get("file.log.transfer.association") + ":" + fileName)
|
||||
.build().getLogDTO();
|
||||
|
||||
operationLogService.add(dto);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,329 @@
|
|||
package io.metersphere.project.service;
|
||||
|
||||
import io.metersphere.project.domain.FileAssociation;
|
||||
import io.metersphere.project.domain.FileAssociationExample;
|
||||
import io.metersphere.project.domain.FileMetadata;
|
||||
import io.metersphere.project.dto.filemanagement.FileAssociationSource;
|
||||
import io.metersphere.project.dto.filemanagement.FileLogRecord;
|
||||
import io.metersphere.project.dto.filemanagement.response.FileAssociationResponse;
|
||||
import io.metersphere.project.dto.filemanagement.response.FileInformationResponse;
|
||||
import io.metersphere.project.mapper.ExtFileAssociationMapper;
|
||||
import io.metersphere.project.mapper.FileAssociationMapper;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.util.FileAssociationSourceUtil;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.ibatis.session.ExecutorType;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.mybatis.spring.SqlSessionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class FileAssociationService {
|
||||
|
||||
@Resource
|
||||
private FileAssociationMapper fileAssociationMapper;
|
||||
@Resource
|
||||
private FileMetadataService fileMetadataService;
|
||||
@Resource
|
||||
private FileAssociationLogService fileAssociationLogService;
|
||||
@Resource
|
||||
private SqlSessionFactory sqlSessionFactory;
|
||||
@Resource
|
||||
private ExtFileAssociationMapper extFileAssociationMapper;
|
||||
|
||||
/**
|
||||
* 通过文件ID,检查该文件所有版本对应的资源关联关系
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public List<FileAssociationResponse> selectFileAllVersionAssociation(String id) {
|
||||
FileInformationResponse fileMetadata = fileMetadataService.getFileInformation(id);
|
||||
if (fileMetadata.getId() == null) {
|
||||
throw new MSException(Translator.get("file.not.exist"));
|
||||
}
|
||||
//通过引用ID查找关联数据
|
||||
FileAssociationExample example = new FileAssociationExample();
|
||||
example.createCriteria().andFileRefIdEqualTo(fileMetadata.getRefId());
|
||||
List<FileAssociation> associationList = fileAssociationMapper.selectByExample(example);
|
||||
//查找文件信息
|
||||
Map<String,FileMetadata> fileIdMap = this.getFileIdMap( associationList.stream().map(FileAssociation::getFileId).collect(Collectors.toList()));
|
||||
//查找资源信息
|
||||
Map<String,String> sourceIdNameMap = this.getAssociationSourceMap(
|
||||
associationList.stream().collect(
|
||||
Collectors.groupingBy(FileAssociation::getSourceType,Collectors.mapping(FileAssociation::getSourceId,Collectors.toList()))
|
||||
));
|
||||
|
||||
//组装返回参数
|
||||
List<FileAssociationResponse> responseList = new ArrayList<>();
|
||||
associationList.forEach(item -> {
|
||||
if(fileIdMap.containsKey(item.getFileId())){
|
||||
FileAssociationResponse response = new FileAssociationResponse();
|
||||
response.setId(item.getId());
|
||||
response.setSourceId(item.getSourceId());
|
||||
response.setFileId(item.getFileId());
|
||||
response.setSourceName(sourceIdNameMap.get(item.getSourceId()));
|
||||
response.setSourceType(item.getSourceType());
|
||||
response.setFileVersion(fileIdMap.get(item.getFileId()).getFileVersion());
|
||||
responseList.add(response);
|
||||
}
|
||||
});
|
||||
return responseList;
|
||||
}
|
||||
|
||||
private Map<String, FileMetadata> getFileIdMap(List<String> fileIdList) {
|
||||
if(CollectionUtils.isEmpty(fileIdList)){
|
||||
return new HashMap<>();
|
||||
}else {
|
||||
List<FileMetadata> fileMetadataList = fileMetadataService.selectByList(fileIdList);
|
||||
return fileMetadataList.stream().collect(Collectors.toMap(FileMetadata::getId, item -> item));
|
||||
}
|
||||
}
|
||||
|
||||
//通过资源类型Map查找关联表
|
||||
private Map<String, String> getAssociationSourceMap(Map<String, List<String>> sourceTypeToIdMap) {
|
||||
List<FileAssociationSource> sourceQueryList = new ArrayList<>();
|
||||
for (Map.Entry<String, List<String>> entry : sourceTypeToIdMap.entrySet()) {
|
||||
String sourceType =entry.getKey();
|
||||
sourceQueryList.addAll(
|
||||
extFileAssociationMapper.selectAssociationSourceBySourceTableAndIdList(FileAssociationSourceUtil.getQuerySql(sourceType),entry.getValue()));
|
||||
}
|
||||
return sourceQueryList.stream().collect(Collectors.toMap(FileAssociationSource::getSourceId, FileAssociationSource::getSourceName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件版本是否是最新的
|
||||
* @param fileIdList 不是最新的文件ID
|
||||
* @return
|
||||
*/
|
||||
public List<String> checkFilesVersion(List<String> fileIdList){
|
||||
if (CollectionUtils.isEmpty(fileIdList)) {
|
||||
throw new MSException(Translator.get("file.not.exist"));
|
||||
}
|
||||
List<String> updatedFileId = new ArrayList<>();
|
||||
List<FileMetadata> fileMetadataList = fileMetadataService.selectByList(fileIdList);
|
||||
fileMetadataList.forEach(item -> {
|
||||
if (!item.getLatest()) {
|
||||
updatedFileId.add(item.getId());
|
||||
}
|
||||
});
|
||||
return updatedFileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 资源关联文件
|
||||
*
|
||||
* @param sourceId 资源id
|
||||
* @param sourceType 资源类型
|
||||
* @param fileIds 文件id集合
|
||||
* @param fileLogRecord 日志记录相关。包含操作人、日志所属模块、触发日志记录的请求路径和请求方法
|
||||
* @return 本次涉及到关联的关联表ID
|
||||
*/
|
||||
public List<String> association(String sourceId, String sourceType, List<String> fileIds, boolean isOverWrite, @Validated FileLogRecord fileLogRecord) {
|
||||
if (CollectionUtils.isEmpty(fileIds)) {
|
||||
throw new MSException(Translator.get("file.not.exist"));
|
||||
}
|
||||
FileAssociationSource source = extFileAssociationMapper.selectNameBySourceTableAndId(FileAssociationSourceUtil.getQuerySql(sourceType),sourceId);
|
||||
this.validateSourceName(source);
|
||||
|
||||
|
||||
List<FileMetadata> fileMetadataList = fileMetadataService.selectByList(fileIds);
|
||||
if (fileMetadataList.size() != fileIds.size()) {
|
||||
throw new MSException(Translator.get("file.some.not.exist"));
|
||||
}
|
||||
|
||||
//校验文件是否已经关联
|
||||
FileAssociationExample example = new FileAssociationExample();
|
||||
example.createCriteria().andSourceIdEqualTo(sourceId);
|
||||
List<FileAssociation> associationdList = fileAssociationMapper.selectByExample(example);
|
||||
Map<String,FileAssociation> refIdFileAssociationMap = associationdList.stream().collect(Collectors.toMap(FileAssociation::getFileRefId, item -> item));
|
||||
|
||||
Map<FileAssociation,FileMetadata> updateAssociationMap = new HashMap<>();
|
||||
List<FileMetadata> addFileList = new ArrayList<>();
|
||||
for (FileMetadata fileMetadata : fileMetadataList) {
|
||||
FileAssociation fileAssociation = refIdFileAssociationMap.get(fileMetadata.getRefId());
|
||||
if(fileAssociation == null){
|
||||
addFileList.add(fileMetadata);
|
||||
}else if(!StringUtils.equals(fileAssociation.getFileId(),fileMetadata.getId())){
|
||||
updateAssociationMap.put(fileAssociation,fileMetadata);
|
||||
}
|
||||
}
|
||||
List<String> associationId = new ArrayList<>();
|
||||
associationId.addAll(this.createFileAssociation(addFileList,sourceId,source.getSourceName(),sourceType,fileLogRecord));
|
||||
if(isOverWrite){
|
||||
associationId.addAll(this.updateFileAssociation(updateAssociationMap,source.getSourceName(),fileLogRecord));
|
||||
}
|
||||
return associationId;
|
||||
}
|
||||
private Collection<String> createFileAssociation(List<FileMetadata> addFileList, String sourceId, String sourceName,String sourceType, @Validated FileLogRecord logRecord) {
|
||||
FileAssociationSourceUtil.validate(sourceType);
|
||||
if(CollectionUtils.isNotEmpty(addFileList)){
|
||||
List<FileAssociation> createFile = new ArrayList<>();
|
||||
long operatorTime = System.currentTimeMillis();
|
||||
addFileList.forEach(item -> {
|
||||
FileAssociation fileAssociation = new FileAssociation();
|
||||
fileAssociation.setId(IDGenerator.nextStr());
|
||||
fileAssociation.setFileId(item.getId());
|
||||
fileAssociation.setFileRefId(item.getRefId());
|
||||
fileAssociation.setSourceId(sourceId);
|
||||
fileAssociation.setSourceType(sourceType);
|
||||
fileAssociation.setCreateTime(operatorTime);
|
||||
fileAssociation.setCreateUser(logRecord.getOperator());
|
||||
fileAssociation.setUpdateTime(operatorTime);
|
||||
fileAssociation.setUpdateUser(logRecord.getOperator());
|
||||
fileAssociation.setFileVersion(item.getFileVersion());
|
||||
createFile.add(fileAssociation);
|
||||
});
|
||||
fileAssociationMapper.batchInsert(createFile);
|
||||
fileAssociationLogService.saveBatchInsertLog(sourceName,addFileList,logRecord);
|
||||
return createFile.stream().map(FileAssociation::getId).collect(Collectors.toList());
|
||||
}else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
private Collection<String> updateFileAssociation(Map<FileAssociation, FileMetadata> updateAssociationMap,String sourceName,@Validated FileLogRecord logRecord) {
|
||||
if(MapUtils.isNotEmpty(updateAssociationMap)){
|
||||
long operatorTime = System.currentTimeMillis();
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
FileAssociationMapper batchUpdateMapper = sqlSession.getMapper(FileAssociationMapper.class);
|
||||
for (Map.Entry<FileAssociation, FileMetadata> entry : updateAssociationMap.entrySet()) {
|
||||
FileAssociation association = entry.getKey();
|
||||
FileMetadata metadata = entry.getValue();
|
||||
association.setFileId(metadata.getId());
|
||||
association.setFileVersion(metadata.getFileVersion());
|
||||
association.setUpdateUser(logRecord.getOperator());
|
||||
association.setUpdateTime(operatorTime);
|
||||
batchUpdateMapper.updateByPrimaryKeySelective(association);
|
||||
}
|
||||
sqlSession.flushStatements();
|
||||
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
||||
fileAssociationLogService.saveBatchUpdateLog(sourceName,updateAssociationMap.values(),logRecord);
|
||||
return updateAssociationMap.keySet().stream().map(FileAssociation::getId).collect(Collectors.toList());
|
||||
}else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将资源关联的文件更新到最新版本
|
||||
* @param fileAssociationId 关联表ID
|
||||
* @param fileLogRecord 日志记录相关
|
||||
* @return 更新后的文件ID
|
||||
*/
|
||||
public String upgrade(String fileAssociationId,@Validated FileLogRecord fileLogRecord){
|
||||
FileAssociation fileAssociation = fileAssociationMapper.selectByPrimaryKey(fileAssociationId);
|
||||
if(fileAssociation == null){
|
||||
throw new MSException(Translator.get("file.association.not.exist"));
|
||||
}
|
||||
|
||||
FileMetadata newFileMetadata = this.getNewVersionFileMetadata(fileAssociation.getFileId());
|
||||
if(StringUtils.equals(newFileMetadata.getId(),fileAssociation.getFileId())){
|
||||
return fileAssociation.getFileId();
|
||||
}else {
|
||||
fileAssociation.setFileId(newFileMetadata.getId());
|
||||
fileAssociation.setFileVersion(newFileMetadata.getFileVersion());
|
||||
fileAssociationMapper.updateByPrimaryKeySelective(fileAssociation);
|
||||
FileAssociationSource source = extFileAssociationMapper.selectNameBySourceTableAndId(FileAssociationSourceUtil.getQuerySql(fileAssociation.getSourceType()),fileAssociation.getSourceId());
|
||||
this.validateSourceName(source);
|
||||
fileAssociationLogService.saveUpdateLog(source.getSourceName(),newFileMetadata,fileLogRecord);
|
||||
return newFileMetadata.getId();
|
||||
}
|
||||
}
|
||||
|
||||
private FileMetadata getNewVersionFileMetadata(String fileId){
|
||||
FileMetadata fileMetadata = fileMetadataService.selectById(fileId);
|
||||
if(fileMetadata == null){
|
||||
throw new MSException(Translator.get("file.not.exist"));
|
||||
}
|
||||
FileMetadata newVersionFileMetadata = fileMetadataService.selectLatestFileByRefId(fileMetadata.getRefId());
|
||||
return newVersionFileMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消关联
|
||||
* @param idList 取消关联的id
|
||||
* @param logRecord 日志记录相关
|
||||
* @return
|
||||
*/
|
||||
public int deleteBySourceId(List<String> idList, @Validated FileLogRecord logRecord){
|
||||
if(CollectionUtils.isEmpty(idList)){
|
||||
return 0;
|
||||
}
|
||||
FileAssociationExample example = new FileAssociationExample();
|
||||
example.createCriteria().andIdIn(idList);
|
||||
List<FileAssociation> fileAssociationList = fileAssociationMapper.selectByExample(example);
|
||||
Map<String,List<String>> sourceToFileNameMap = this.genSourceNameFileNameMap(fileAssociationList);
|
||||
int deleteCount = fileAssociationMapper.deleteByExample(example);
|
||||
if(MapUtils.isNotEmpty(sourceToFileNameMap)){
|
||||
fileAssociationLogService.saveDeleteLog(sourceToFileNameMap,logRecord);
|
||||
}
|
||||
return deleteCount;
|
||||
}
|
||||
|
||||
private Map<String, List<String>> genSourceNameFileNameMap(List<FileAssociation> fileAssociationList) {
|
||||
Map<String,List<String>> sourceNameFileNameMap = new HashMap<>();
|
||||
Map<String,String> fileIdMap = new HashMap<>();
|
||||
for (FileAssociation fileAssociation:fileAssociationList){
|
||||
FileAssociationSource source = extFileAssociationMapper.selectNameBySourceTableAndId(FileAssociationSourceUtil.getQuerySql(fileAssociation.getSourceType()),fileAssociation.getSourceId());
|
||||
this.validateSourceName(source);
|
||||
String fileName = null;
|
||||
if(fileIdMap.containsKey(fileAssociation.getFileId())){
|
||||
fileName = fileIdMap.get(fileAssociation.getFileId());
|
||||
}else {
|
||||
FileMetadata fileMetadata = fileMetadataService.selectById(fileAssociation.getFileId());
|
||||
if(fileMetadata != null){
|
||||
fileName = fileMetadata.getName();
|
||||
fileIdMap.put(fileMetadata.getId(),fileName);
|
||||
}
|
||||
}
|
||||
if(StringUtils.isNotEmpty(fileName)){
|
||||
if(sourceNameFileNameMap.containsKey(source.getSourceName())){
|
||||
sourceNameFileNameMap.get(source.getSourceName()).add(fileName);
|
||||
}else {
|
||||
List<String> fileNameList = new ArrayList<>();
|
||||
fileNameList.add(fileName);
|
||||
sourceNameFileNameMap.put(source.getSourceName(), fileNameList);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sourceNameFileNameMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转存并关联文件
|
||||
* @param fileName 文件名称(含后缀)
|
||||
* @param fileBytes 文件字节流
|
||||
* @param sourceId 要关联的资源ID
|
||||
* @param sourceType 要关联的资源名称
|
||||
* @param fileLogRecord 日志记录相关
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public String transferAndAssociation(String fileName,byte[] fileBytes,String sourceId,String sourceType, @Validated FileLogRecord fileLogRecord) throws Exception {
|
||||
FileAssociationSource source = extFileAssociationMapper.selectNameBySourceTableAndId(FileAssociationSourceUtil.getQuerySql(sourceType),sourceId);
|
||||
this.validateSourceName(source);
|
||||
String fileId = fileMetadataService.transferFile(fileName, fileLogRecord.getProjectId(), fileLogRecord.getOperator(),fileBytes);
|
||||
List<String> accociationList = new ArrayList<>();
|
||||
accociationList.add(fileId);
|
||||
this.association(sourceId, sourceType, accociationList, false, fileLogRecord);
|
||||
fileAssociationLogService.saveTransferAssociationLog(sourceId,fileName,source.getSourceName(),fileLogRecord);
|
||||
return fileId;
|
||||
}
|
||||
|
||||
private void validateSourceName(FileAssociationSource source){
|
||||
if(source == null){
|
||||
throw new MSException(Translator.get("file.association.source.not.exist"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,12 +60,12 @@ public class FileMetadataLogService {
|
|||
.path("/project/file/re-upload")
|
||||
.sourceId(module.getId())
|
||||
.content(Translator.get("file.log.re-upload") + " " + module.getName())
|
||||
.originalValue(JSON.toJSONBytes(module))
|
||||
.createUser(operator)
|
||||
.build().getLogDTO();
|
||||
operationLogService.add(dto);
|
||||
}
|
||||
public void saveUpdateLog(FileMetadata module, String projectId, String operator) {
|
||||
|
||||
public void saveUpdateLog(FileMetadata oldFile, FileMetadata newFile, String projectId, String operator) {
|
||||
Project project = projectMapper.selectByPrimaryKey(projectId);
|
||||
LogDTO dto = LogDTOBuilder.builder()
|
||||
.projectId(projectId)
|
||||
|
@ -74,9 +74,10 @@ public class FileMetadataLogService {
|
|||
.module(logModule)
|
||||
.method(HttpMethodConstants.POST.name())
|
||||
.path("/project/file/update")
|
||||
.sourceId(module.getId())
|
||||
.content(module.getName())
|
||||
.originalValue(JSON.toJSONBytes(module))
|
||||
.sourceId(newFile.getId())
|
||||
.content(newFile.getName())
|
||||
.originalValue(JSON.toJSONBytes(oldFile))
|
||||
.modifiedValue(JSON.toJSONBytes(newFile))
|
||||
.createUser(operator)
|
||||
.build().getLogDTO();
|
||||
operationLogService.add(dto);
|
||||
|
@ -115,7 +116,6 @@ public class FileMetadataLogService {
|
|||
.path("/project/file/jar-file-status")
|
||||
.sourceId(module.getId())
|
||||
.content(Translator.get("change.jar.enable") + ":" + enable)
|
||||
.originalValue(JSON.toJSONBytes(module))
|
||||
.createUser(operator)
|
||||
.build().getLogDTO();
|
||||
operationLogService.add(dto);
|
||||
|
@ -162,7 +162,7 @@ public class FileMetadataLogService {
|
|||
operationLogService.add(dto);
|
||||
}
|
||||
|
||||
public void saveFilePullLog(FileMetadata module, String operator) {
|
||||
public void saveFilePullLog(FileMetadata oldFile, FileMetadata module, String operator) {
|
||||
Project project = projectMapper.selectByPrimaryKey(module.getProjectId());
|
||||
LogDTO dto = LogDTOBuilder.builder()
|
||||
.projectId(module.getProjectId())
|
||||
|
@ -173,7 +173,8 @@ public class FileMetadataLogService {
|
|||
.path("/project/file/repository/pull-file")
|
||||
.sourceId(module.getId())
|
||||
.content(Translator.get("file.log.pull") + " " + module.getName())
|
||||
.originalValue(JSON.toJSONBytes(module))
|
||||
.originalValue(JSON.toJSONBytes(oldFile))
|
||||
.modifiedValue(JSON.toJSONBytes(module))
|
||||
.createUser(operator)
|
||||
.build().getLogDTO();
|
||||
operationLogService.add(dto);
|
||||
|
|
|
@ -18,11 +18,14 @@ import io.metersphere.project.utils.FileDownloadUtils;
|
|||
import io.metersphere.sdk.constants.ModuleConstants;
|
||||
import io.metersphere.sdk.constants.StorageType;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.util.CommonBeanFactory;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.TempFileUtils;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.dto.sdk.RemoteFileAttachInfo;
|
||||
import io.metersphere.system.file.FileRepository;
|
||||
import io.metersphere.system.file.FileRequest;
|
||||
import io.metersphere.system.file.MinioRepository;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import io.metersphere.system.utils.GitRepositoryUtil;
|
||||
import io.metersphere.system.utils.PageUtils;
|
||||
|
@ -70,7 +73,11 @@ public class FileMetadataService {
|
|||
@Value("${metersphere.file.batch-download-max:600MB}")
|
||||
private DataSize maxFileSize;
|
||||
|
||||
public FileInformationResponse get(String id) {
|
||||
public FileMetadata selectById(String id) {
|
||||
return fileMetadataMapper.selectByPrimaryKey(id);
|
||||
}
|
||||
|
||||
public FileInformationResponse getFileInformation(String id) {
|
||||
FileMetadata fileMetadata = extFileMetadataMapper.getById(id);
|
||||
FileInformationResponse dto = new FileInformationResponse(fileMetadata);
|
||||
initModuleName(dto);
|
||||
|
@ -115,7 +122,7 @@ public class FileMetadataService {
|
|||
}
|
||||
}
|
||||
|
||||
public FileMetadata saveFileMetadata(String projectId, String moduleId, String filePath, String storage, String operator, long size, boolean enable) {
|
||||
public FileMetadata genFileMetadata(String filePath, String storage, long size, boolean enable, String projectId, String moduleId, String operator) {
|
||||
String fileName = TempFileUtils.getFileNameByPath(filePath);
|
||||
FileMetadata fileMetadata = new FileMetadata();
|
||||
if (StringUtils.lastIndexOf(fileName, ".") > 0) {
|
||||
|
@ -131,7 +138,16 @@ public class FileMetadataService {
|
|||
this.checkEnableFile(fileMetadata.getType());
|
||||
}
|
||||
//检查处理后的用户名合法性
|
||||
this.checkFileName(null, fileMetadata.getName(), projectId);
|
||||
if (StringUtils.equals(storage, StorageType.MINIO.name())) {
|
||||
this.checkMinIOFileName(null, fileMetadata.getName(), projectId);
|
||||
} else {
|
||||
//Git: 存储库下的文件路径不能重复
|
||||
FileMetadataExample example = new FileMetadataExample();
|
||||
example.createCriteria().andPathEqualTo(filePath).andProjectIdEqualTo(projectId).andStorageEqualTo(StorageType.GIT.name()).andModuleIdEqualTo(moduleId);
|
||||
if (fileMetadataMapper.countByExample(example) > 0) {
|
||||
throw new MSException(Translator.get("file.name.exist") + ":" + fileName);
|
||||
}
|
||||
}
|
||||
|
||||
fileMetadata.setId(IDGenerator.nextStr());
|
||||
fileMetadata.setStorage(storage);
|
||||
|
@ -147,7 +163,6 @@ public class FileMetadataService {
|
|||
fileMetadata.setLatest(true);
|
||||
fileMetadata.setRefId(fileMetadata.getId());
|
||||
fileMetadata.setEnable(false);
|
||||
fileMetadataMapper.insert(fileMetadata);
|
||||
return fileMetadata;
|
||||
}
|
||||
|
||||
|
@ -157,31 +172,95 @@ public class FileMetadataService {
|
|||
|
||||
String fileName = StringUtils.trim(uploadFile.getOriginalFilename());
|
||||
|
||||
FileMetadata fileMetadata = this.saveFileMetadata(request.getProjectId(), request.getModuleId(), fileName, StorageType.MINIO.name(), operator, uploadFile.getSize(), request.isEnable());
|
||||
|
||||
//记录日志
|
||||
fileMetadataLogService.saveUploadLog(fileMetadata, operator);
|
||||
FileMetadata fileMetadata = this.genFileMetadata(fileName, StorageType.MINIO.name(), uploadFile.getSize(), request.isEnable(), request.getProjectId(), request.getModuleId(), operator);
|
||||
|
||||
// 上传文件
|
||||
String filePath = this.uploadFile(fileMetadata, uploadFile);
|
||||
FileMetadata updateFileMetadata = new FileMetadata();
|
||||
updateFileMetadata.setId(fileMetadata.getId());
|
||||
updateFileMetadata.setPath(filePath);
|
||||
updateFileMetadata.setFileVersion(fileMetadata.getId());
|
||||
fileMetadataMapper.updateByPrimaryKeySelective(updateFileMetadata);
|
||||
|
||||
fileMetadata.setPath(filePath);
|
||||
fileMetadata.setFileVersion(fileMetadata.getId());
|
||||
fileMetadataMapper.insert(fileMetadata);
|
||||
//记录日志
|
||||
fileMetadataLogService.saveUploadLog(fileMetadata, operator);
|
||||
|
||||
return fileMetadata.getId();
|
||||
}
|
||||
|
||||
private void checkFileName(String id, String fileName, String projectId) {
|
||||
|
||||
/**
|
||||
* 文件转存
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @param projectId 项目ID
|
||||
* @param operator 操作人
|
||||
* @param fileBytes 文件字节
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public String transferFile(String fileName, String projectId, String operator, byte[] fileBytes) throws Exception {
|
||||
if (StringUtils.isBlank(fileName)) {
|
||||
throw new MSException(Translator.get("file.name.cannot.be.empty"));
|
||||
}
|
||||
fileName = this.genTransferFileName(StringUtils.trim(fileName), projectId);
|
||||
String moduleId = ModuleConstants.NODE_TYPE_DEFAULT;
|
||||
|
||||
FileMetadata fileMetadata = this.genFileMetadata(fileName, StorageType.MINIO.name(), fileBytes.length, false, projectId, moduleId, operator);
|
||||
|
||||
FileRequest uploadFileRequest = new FileRequest();
|
||||
uploadFileRequest.setFileName(fileMetadata.getId());
|
||||
uploadFileRequest.setProjectId(fileMetadata.getProjectId());
|
||||
uploadFileRequest.setStorage(StorageType.MINIO.name());
|
||||
|
||||
FileRepository minio = CommonBeanFactory.getBean(MinioRepository.class);
|
||||
String filePath = minio.saveFile(fileBytes, uploadFileRequest);
|
||||
fileMetadata.setPath(filePath);
|
||||
fileMetadata.setFileVersion(fileMetadata.getId());
|
||||
fileMetadataMapper.insert(fileMetadata);
|
||||
return fileMetadata.getId();
|
||||
}
|
||||
|
||||
private String genTransferFileName(String fullFileName, String projectId) {
|
||||
if (StringUtils.containsAny(fullFileName, "/")) {
|
||||
throw new MSException(Translator.get("file.name.error"));
|
||||
}
|
||||
|
||||
String fileName;
|
||||
String fileType = null;
|
||||
if (StringUtils.lastIndexOf(fullFileName, ".") > 0) {
|
||||
//采用这种判断方式,可以避免将隐藏文件的后缀名作为文件类型
|
||||
fileName = StringUtils.substring(fullFileName, 0, fullFileName.lastIndexOf("."));
|
||||
fileType = StringUtils.substring(fullFileName, fullFileName.lastIndexOf(".") + 1);
|
||||
} else {
|
||||
fileName = fullFileName;
|
||||
}
|
||||
|
||||
FileMetadataExample example = new FileMetadataExample();
|
||||
example.createCriteria().andNameEqualTo(fileName).andProjectIdEqualTo(projectId);
|
||||
|
||||
int fileIndex = 0;
|
||||
String originFileName = fileName;
|
||||
while (fileMetadataMapper.countByExample(example) > 0) {
|
||||
fileIndex++;
|
||||
fileName = originFileName + "(" + fileIndex + ")";
|
||||
example = new FileMetadataExample();
|
||||
example.createCriteria().andNameEqualTo(fileName).andProjectIdEqualTo(projectId);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(fileType)) {
|
||||
fileName = fileName + "." + fileType;
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private void checkMinIOFileName(String id, String fileName, String projectId) {
|
||||
if (StringUtils.isBlank(fileName)) {
|
||||
throw new MSException(Translator.get("file.name.cannot.be.empty"));
|
||||
}
|
||||
FileMetadataExample example = new FileMetadataExample();
|
||||
if (StringUtils.isBlank(id)) {
|
||||
example.createCriteria().andNameEqualTo(fileName).andProjectIdEqualTo(projectId);
|
||||
example.createCriteria().andNameEqualTo(fileName).andProjectIdEqualTo(projectId).andStorageEqualTo(StorageType.MINIO.name());
|
||||
} else {
|
||||
example.createCriteria().andNameEqualTo(fileName).andProjectIdEqualTo(projectId).andIdNotEqualTo(id);
|
||||
example.createCriteria().andNameEqualTo(fileName).andProjectIdEqualTo(projectId).andIdNotEqualTo(id).andStorageEqualTo(StorageType.MINIO.name());
|
||||
}
|
||||
if (fileMetadataMapper.countByExample(example) > 0) {
|
||||
throw new MSException(Translator.get("file.name.exist") + ":" + fileName);
|
||||
|
@ -263,7 +342,7 @@ public class FileMetadataService {
|
|||
updateExample.setDescription(request.getDescription());
|
||||
updateExample.setModuleId(request.getModuleId());
|
||||
if (StringUtils.isNotBlank(request.getName())) {
|
||||
this.checkFileName(request.getId(), request.getName(), fileMetadata.getProjectId());
|
||||
this.checkMinIOFileName(request.getId(), request.getName(), fileMetadata.getProjectId());
|
||||
updateExample.setName(request.getName());
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(request.getTags())) {
|
||||
|
@ -278,8 +357,10 @@ public class FileMetadataService {
|
|||
updateExample.setUpdateUser(operator);
|
||||
updateExample.setUpdateTime(System.currentTimeMillis());
|
||||
fileMetadataMapper.updateByPrimaryKeySelective(updateExample);
|
||||
|
||||
FileMetadata newFile = fileMetadataMapper.selectByPrimaryKey(request.getId());
|
||||
//记录日志
|
||||
fileMetadataLogService.saveUpdateLog(fileMetadata, fileMetadata.getProjectId(), operator);
|
||||
fileMetadataLogService.saveUpdateLog(fileMetadata, newFile, fileMetadata.getProjectId(), operator);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -491,6 +572,7 @@ public class FileMetadataService {
|
|||
if (!StringUtils.equals(gitFileAttachInfo.getCommitId(), metadataRepository.getCommitId())) {
|
||||
this.setFileVersionIsOld(oldFile, operator);
|
||||
FileMetadata fileMetadata = this.genNewVersion(oldFile, operator);
|
||||
fileMetadata.setFileVersion(gitFileAttachInfo.getCommitId());
|
||||
fileMetadata.setSize(gitFileAttachInfo.getSize());
|
||||
fileMetadataMapper.insert(fileMetadata);
|
||||
returnFileId = fileMetadata.getId();
|
||||
|
@ -503,10 +585,27 @@ public class FileMetadataService {
|
|||
fileMetadataRepositoryMapper.insert(fileMetadataRepository);
|
||||
|
||||
//记录日志
|
||||
fileMetadataLogService.saveFilePullLog(fileMetadata, operator);
|
||||
fileMetadataLogService.saveFilePullLog(oldFile, fileMetadata, operator);
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnFileId;
|
||||
}
|
||||
|
||||
public List<FileMetadata> selectByList(List<String> fileIds) {
|
||||
FileMetadataExample example = new FileMetadataExample();
|
||||
example.createCriteria().andIdIn(fileIds);
|
||||
return fileMetadataMapper.selectByExample(example);
|
||||
}
|
||||
|
||||
public FileMetadata selectLatestFileByRefId(String refId) {
|
||||
FileMetadataExample fileMetadataExample = new FileMetadataExample();
|
||||
fileMetadataExample.createCriteria().andRefIdEqualTo(refId).andLatestEqualTo(true);
|
||||
List<FileMetadata> fileMetadataList = fileMetadataMapper.selectByExample(fileMetadataExample);
|
||||
if (CollectionUtils.isNotEmpty(fileMetadataList)) {
|
||||
return fileMetadataList.get(0);
|
||||
} else {
|
||||
throw new MSException(Translator.get("latest.file.not.exist"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ public class FileModuleLogService {
|
|||
operationLogService.add(dto);
|
||||
}
|
||||
|
||||
public void saveUpdateLog(FileModule module, String projectId, String operator) {
|
||||
public void saveUpdateLog(FileModule oldModule, FileModule newModule, String projectId, String operator) {
|
||||
Project project = projectMapper.selectByPrimaryKey(projectId);
|
||||
LogDTO dto = LogDTOBuilder.builder()
|
||||
.projectId(projectId)
|
||||
|
@ -73,26 +73,28 @@ public class FileModuleLogService {
|
|||
.module(OperationLogModule.PROJECT_FILE_MANAGEMENT)
|
||||
.method(HttpMethodConstants.POST.name())
|
||||
.path("/project/file-module/update")
|
||||
.sourceId(module.getId())
|
||||
.content(module.getName())
|
||||
.originalValue(JSON.toJSONBytes(module))
|
||||
.sourceId(newModule.getId())
|
||||
.content(newModule.getName())
|
||||
.originalValue(JSON.toJSONBytes(oldModule))
|
||||
.modifiedValue(JSON.toJSONBytes(newModule))
|
||||
.createUser(operator)
|
||||
.build().getLogDTO();
|
||||
operationLogService.add(dto);
|
||||
}
|
||||
|
||||
public void saveUpdateRepositoryLog(FileRepositoryLog fileRepositoryLog, String operator) {
|
||||
Project project = projectMapper.selectByPrimaryKey(fileRepositoryLog.getProjectId());
|
||||
public void saveUpdateRepositoryLog(FileRepositoryLog oldRepositoryLog, FileRepositoryLog newRepositoryLog, String operator) {
|
||||
Project project = projectMapper.selectByPrimaryKey(newRepositoryLog.getProjectId());
|
||||
LogDTO dto = LogDTOBuilder.builder()
|
||||
.projectId(fileRepositoryLog.getProjectId())
|
||||
.projectId(newRepositoryLog.getProjectId())
|
||||
.organizationId(project.getOrganizationId())
|
||||
.type(OperationLogType.UPDATE.name())
|
||||
.module(OperationLogModule.PROJECT_FILE_MANAGEMENT)
|
||||
.method(HttpMethodConstants.POST.name())
|
||||
.path("/project/file/repository/update-repository")
|
||||
.sourceId(fileRepositoryLog.getId())
|
||||
.content(fileRepositoryLog.getName())
|
||||
.originalValue(JSON.toJSONBytes(fileRepositoryLog))
|
||||
.sourceId(newRepositoryLog.getId())
|
||||
.content(newRepositoryLog.getName())
|
||||
.originalValue(JSON.toJSONBytes(oldRepositoryLog))
|
||||
.modifiedValue(JSON.toJSONBytes(newRepositoryLog))
|
||||
.createUser(operator)
|
||||
.build().getLogDTO();
|
||||
operationLogService.add(dto);
|
||||
|
@ -142,7 +144,6 @@ public class FileModuleLogService {
|
|||
.path("/project/file-module/move")
|
||||
.sourceId(moveNode.getId())
|
||||
.content(logContent)
|
||||
.originalValue(JSON.toJSONBytes(moveNode))
|
||||
.createUser(operator)
|
||||
.build().getLogDTO();
|
||||
operationLogService.add(dto);
|
||||
|
|
|
@ -131,8 +131,9 @@ public class FileModuleService extends ModuleTreeService implements CleanupProje
|
|||
updateModule.setUpdateTime(System.currentTimeMillis());
|
||||
updateModule.setUpdateUser(userId);
|
||||
fileModuleMapper.updateByPrimaryKeySelective(updateModule);
|
||||
FileModule newModule = fileModuleMapper.selectByPrimaryKey(request.getId());
|
||||
//记录日志
|
||||
fileModuleLogService.saveUpdateLog(updateModule, module.getProjectId(), userId);
|
||||
fileModuleLogService.saveUpdateLog(module, newModule, module.getProjectId(), userId);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import io.metersphere.project.dto.filemanagement.request.FileRepositoryCreateReq
|
|||
import io.metersphere.project.dto.filemanagement.request.FileRepositoryUpdateRequest;
|
||||
import io.metersphere.project.dto.filemanagement.request.RepositoryFileAddRequest;
|
||||
import io.metersphere.project.dto.filemanagement.response.FileRepositoryResponse;
|
||||
import io.metersphere.project.mapper.FileMetadataMapper;
|
||||
import io.metersphere.project.mapper.FileMetadataRepositoryMapper;
|
||||
import io.metersphere.project.mapper.FileModuleRepositoryMapper;
|
||||
import io.metersphere.sdk.constants.ModuleConstants;
|
||||
|
@ -37,6 +38,8 @@ public class FileRepositoryService extends FileModuleService {
|
|||
@Resource
|
||||
private FileMetadataService fileMetadataService;
|
||||
@Resource
|
||||
private FileMetadataMapper fileMetadataMapper;
|
||||
@Resource
|
||||
private FileModuleRepositoryMapper fileModuleRepositoryMapper;
|
||||
@Resource
|
||||
private FileMetadataRepositoryMapper fileMetadataRepositoryMapper;
|
||||
|
@ -95,6 +98,9 @@ public class FileRepositoryService extends FileModuleService {
|
|||
if (ObjectUtils.anyNull(fileModule, repository)) {
|
||||
throw new MSException(Translator.get("file_repository.connect.error"));
|
||||
}
|
||||
|
||||
FileRepositoryLog oldLog = new FileRepositoryLog(fileModule, repository);
|
||||
|
||||
this.connect(repository.getUrl(),
|
||||
request.getToken() == null ? repository.getToken() : request.getToken(),
|
||||
request.getUserName() == null ? repository.getUserName() : request.getUserName());
|
||||
|
@ -115,8 +121,9 @@ public class FileRepositoryService extends FileModuleService {
|
|||
}
|
||||
fileModuleRepositoryMapper.updateByPrimaryKeySelective(repository);
|
||||
}
|
||||
|
||||
//记录日志
|
||||
fileModuleLogService.saveUpdateRepositoryLog(new FileRepositoryLog(fileModule, repository), operator);
|
||||
fileModuleLogService.saveUpdateRepositoryLog(oldLog, new FileRepositoryLog(fileModule, repository), operator);
|
||||
}
|
||||
|
||||
private void checkPlatForm(String platform) {
|
||||
|
@ -137,9 +144,11 @@ public class FileRepositoryService extends FileModuleService {
|
|||
if (fileAttachInfo == null) {
|
||||
throw new MSException(Translator.get("file.not.exist"));
|
||||
}
|
||||
FileMetadata fileMetadata = fileMetadataService.genFileMetadata(request.getFilePath(), StorageType.GIT.name(), fileAttachInfo.getSize(), request.isEnable(),
|
||||
fileModule.getProjectId(), fileModule.getId(), operator);
|
||||
fileMetadata.setFileVersion(fileAttachInfo.getCommitId());
|
||||
fileMetadataMapper.insert(fileMetadata);
|
||||
|
||||
FileMetadata fileMetadata = fileMetadataService.saveFileMetadata(
|
||||
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());
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
package io.metersphere.project.controller.filemanagement;
|
||||
|
||||
import io.metersphere.project.domain.*;
|
||||
import io.metersphere.project.dto.filemanagement.FileLogRecord;
|
||||
import io.metersphere.project.dto.filemanagement.request.*;
|
||||
import io.metersphere.project.dto.filemanagement.response.FileAssociationResponse;
|
||||
import io.metersphere.project.dto.filemanagement.response.FileInformationResponse;
|
||||
import io.metersphere.project.mapper.FileAssociationMapper;
|
||||
import io.metersphere.project.mapper.FileMetadataMapper;
|
||||
import io.metersphere.project.mapper.FileModuleMapper;
|
||||
import io.metersphere.project.service.FileAssociationService;
|
||||
import io.metersphere.project.service.FileModuleService;
|
||||
import io.metersphere.project.utils.FileManagementBaseUtils;
|
||||
import io.metersphere.project.utils.FileManagementRequestUtils;
|
||||
import io.metersphere.sdk.constants.ModuleConstants;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
import io.metersphere.sdk.constants.SessionConstants;
|
||||
import io.metersphere.sdk.constants.StorageType;
|
||||
import io.metersphere.sdk.constants.*;
|
||||
import io.metersphere.sdk.util.FileAssociationSourceUtil;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.TempFileUtils;
|
||||
import io.metersphere.system.base.BaseTest;
|
||||
|
@ -32,6 +34,8 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
|
|||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
import org.springframework.test.context.jdbc.SqlConfig;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
|
@ -41,6 +45,7 @@ import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
|
|||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
@ -62,6 +67,14 @@ public class FileManagementControllerTests extends BaseTest {
|
|||
private static String picFileId;
|
||||
private static String jarFileId;
|
||||
|
||||
private static String fileAssociationOldFileId;
|
||||
private static String fileAssociationNewFileId;
|
||||
private static String fileAssociationNewFilesOne;
|
||||
private static String fileAssociationNewFilesTwo;
|
||||
private static String fileAssociationNewFilesThree;
|
||||
private static String fileAssociationNewFilesFour;
|
||||
private static Map<String, List<String>> sourceAssociationFileMap = new HashMap<>();
|
||||
|
||||
@Resource
|
||||
private FileModuleService fileModuleService;
|
||||
@Resource
|
||||
|
@ -569,12 +582,22 @@ public class FileManagementControllerTests extends BaseTest {
|
|||
this.fileUploadTestSuccess();
|
||||
}
|
||||
for (String key : FILE_ID_PATH.keySet()) {
|
||||
if (StringUtils.isEmpty(fileAssociationNewFilesOne)) {
|
||||
fileAssociationNewFilesOne = key;
|
||||
} else if (StringUtils.isEmpty(fileAssociationNewFilesTwo)) {
|
||||
fileAssociationNewFilesTwo = key;
|
||||
} else if (StringUtils.isEmpty(fileAssociationNewFilesThree)) {
|
||||
fileAssociationNewFilesThree = key;
|
||||
} else if (StringUtils.isEmpty(fileAssociationNewFilesFour)) {
|
||||
fileAssociationNewFilesFour = key;
|
||||
} else {
|
||||
reUploadFileId = key;
|
||||
}
|
||||
}
|
||||
|
||||
FileUploadRequest fileUploadRequest = new FileUploadRequest();
|
||||
fileUploadRequest.setProjectId(project.getId());
|
||||
|
||||
fileAssociationOldFileId = reUploadFileId;
|
||||
//构建参数
|
||||
FileReUploadRequest fileReUploadRequest = new FileReUploadRequest();
|
||||
fileReUploadRequest.setFileId(reUploadFileId);
|
||||
|
@ -600,6 +623,7 @@ public class FileManagementControllerTests extends BaseTest {
|
|||
checkLog(reUploadId, OperationLogType.UPDATE, FileManagementRequestUtils.URL_FILE_RE_UPLOAD);
|
||||
FILE_ID_PATH.put(reUploadId, filePath);
|
||||
FILE_VERSIONS_ID_MAP.put(reUploadId, reUploadFileId);
|
||||
fileAssociationNewFileId = reUploadId;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -922,45 +946,6 @@ public class FileManagementControllerTests extends BaseTest {
|
|||
.andExpect(status().is5xxServerError());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(20)
|
||||
public void fileDeleteSuccess() throws Exception {
|
||||
if (MapUtils.isEmpty(FILE_VERSIONS_ID_MAP)) {
|
||||
this.fileReUploadTestSuccess();
|
||||
}
|
||||
FileBatchProcessRequest fileBatchProcessRequest;
|
||||
//删除指定文件
|
||||
for (Map.Entry<String, String> entry : FILE_VERSIONS_ID_MAP.entrySet()) {
|
||||
String fileMetadataId = entry.getKey();
|
||||
String refId = entry.getValue();
|
||||
|
||||
fileBatchProcessRequest = new FileBatchProcessRequest();
|
||||
fileBatchProcessRequest.setProjectId(project.getId());
|
||||
fileBatchProcessRequest.setSelectIds(new ArrayList<>() {{
|
||||
this.add(fileMetadataId);
|
||||
}});
|
||||
this.requestPostWithOk(FileManagementRequestUtils.URL_FILE_DELETE, fileBatchProcessRequest);
|
||||
|
||||
this.checkFileIsDeleted(fileMetadataId, refId);
|
||||
checkLog(fileMetadataId, OperationLogType.DELETE, FileManagementRequestUtils.URL_FILE_DELETE);
|
||||
}
|
||||
FILE_VERSIONS_ID_MAP.clear();
|
||||
|
||||
//全部删除
|
||||
fileBatchProcessRequest = new FileBatchProcessRequest();
|
||||
fileBatchProcessRequest.setSelectAll(true);
|
||||
fileBatchProcessRequest.setProjectId(project.getId());
|
||||
fileBatchProcessRequest.setExcludeIds(new ArrayList<>() {{
|
||||
this.add(IDGenerator.nextStr());
|
||||
}});
|
||||
this.requestPostWithOk(FileManagementRequestUtils.URL_FILE_DELETE, fileBatchProcessRequest);
|
||||
FileMetadataExample example = new FileMetadataExample();
|
||||
example.createCriteria().andProjectIdEqualTo(project.getId());
|
||||
Assertions.assertEquals(fileMetadataMapper.countByExample(example), 0);
|
||||
//重新上传,用于后续的测试
|
||||
this.fileUploadTestSuccess();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Order(21)
|
||||
|
@ -1082,6 +1067,507 @@ public class FileManagementControllerTests extends BaseTest {
|
|||
this.requestGet(String.format(FileManagementRequestUtils.URL_CHANGE_JAR_ENABLE, picFileId, true));
|
||||
}
|
||||
|
||||
/*
|
||||
30-80之间是测试文件关联的
|
||||
*/
|
||||
@Resource
|
||||
private FileAssociationMapper fileAssociationMapper;
|
||||
@Resource
|
||||
private FileAssociationService fileAssociationService;
|
||||
|
||||
@Test
|
||||
@Order(30)
|
||||
public void fileAssociationCheckFileVersionTest() throws Exception {
|
||||
if (StringUtils.isAnyEmpty(fileAssociationOldFileId, fileAssociationNewFileId, fileAssociationNewFilesOne, fileAssociationNewFilesTwo, fileAssociationNewFilesThree)) {
|
||||
this.fileReUploadTestSuccess();
|
||||
}
|
||||
//1.没有要更新的文件
|
||||
List<String> fileIdList = new ArrayList<>() {{
|
||||
this.add(fileAssociationNewFileId);
|
||||
this.add(fileAssociationNewFilesOne);
|
||||
}};
|
||||
List<String> newVersionFileIdList = fileAssociationService.checkFilesVersion(fileIdList);
|
||||
Assertions.assertTrue(CollectionUtils.isEmpty(newVersionFileIdList));
|
||||
//2.有要更新的文件
|
||||
fileIdList = new ArrayList<>() {{
|
||||
this.add(fileAssociationOldFileId);
|
||||
this.add(fileAssociationNewFilesOne);
|
||||
}};
|
||||
newVersionFileIdList = fileAssociationService.checkFilesVersion(fileIdList);
|
||||
Assertions.assertEquals(newVersionFileIdList.size(), 1);
|
||||
Assertions.assertTrue(newVersionFileIdList.contains(fileAssociationOldFileId));
|
||||
//3.参数为空
|
||||
boolean error = false;
|
||||
try {
|
||||
fileAssociationService.checkFilesVersion(new ArrayList<>());
|
||||
} catch (Exception e) {
|
||||
error = true;
|
||||
}
|
||||
Assertions.assertTrue(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件关联的相关测试。由于要注入sql,拆分多个单元测试方法时无法保证sql的注入性。所以合在一个方法中。
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@Order(31)
|
||||
@Sql(scripts = {"/dml/init_bug.sql"},
|
||||
config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED),
|
||||
executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
|
||||
public void fileAssociationTests() throws Exception {
|
||||
//检查文件版本
|
||||
fileAssociationCheckFileVersionTest();
|
||||
//预备:手动关联缺陷过期文件. bug-id-1和bug-id-2用来后续测试更新, bug-id-3用于本轮测试
|
||||
List<String> oldFileIdList = new ArrayList<>();
|
||||
oldFileIdList.add(this.addFileAssociation("sty-file-association-bug-id-2", "BUG", fileAssociationOldFileId));
|
||||
this.saveSourceAssociationId("sty-file-association-bug-id-2", oldFileIdList);
|
||||
|
||||
oldFileIdList = new ArrayList<>();
|
||||
oldFileIdList.add(this.addFileAssociation("sty-file-association-bug-id-3", "BUG", fileAssociationOldFileId));
|
||||
this.saveSourceAssociationId("sty-file-association-bug-id-3", oldFileIdList);
|
||||
|
||||
oldFileIdList = new ArrayList<>();
|
||||
oldFileIdList.add(this.addFileAssociation("sty-file-association-bug-id-4", "BUG", fileAssociationOldFileId));
|
||||
this.saveSourceAssociationId("sty-file-association-bug-id-4", oldFileIdList);
|
||||
//文件关联
|
||||
this.associationFile();
|
||||
//文件更新
|
||||
this.associationUpgrade();
|
||||
//文件转存并关联
|
||||
this.transferAndAssociation();
|
||||
//文件管理页面-查询关联文件
|
||||
this.fileAssociationControllerPage();
|
||||
//文件管理页面-更新关联文件
|
||||
this.fileAssociationControllerUpgrade();
|
||||
//文件管理页面-取消关联文件
|
||||
this.fileAssociationControllerDelete();
|
||||
//文件取消关联
|
||||
this.associationDelete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(40)
|
||||
public void fileDeleteSuccess() throws Exception {
|
||||
if (MapUtils.isEmpty(FILE_VERSIONS_ID_MAP)) {
|
||||
this.fileReUploadTestSuccess();
|
||||
}
|
||||
FileBatchProcessRequest fileBatchProcessRequest;
|
||||
//删除指定文件
|
||||
for (Map.Entry<String, String> entry : FILE_VERSIONS_ID_MAP.entrySet()) {
|
||||
String fileMetadataId = entry.getKey();
|
||||
String refId = entry.getValue();
|
||||
|
||||
fileBatchProcessRequest = new FileBatchProcessRequest();
|
||||
fileBatchProcessRequest.setProjectId(project.getId());
|
||||
fileBatchProcessRequest.setSelectIds(new ArrayList<>() {{
|
||||
this.add(fileMetadataId);
|
||||
}});
|
||||
this.requestPostWithOk(FileManagementRequestUtils.URL_FILE_DELETE, fileBatchProcessRequest);
|
||||
|
||||
this.checkFileIsDeleted(fileMetadataId, refId);
|
||||
checkLog(fileMetadataId, OperationLogType.DELETE, FileManagementRequestUtils.URL_FILE_DELETE);
|
||||
}
|
||||
FILE_VERSIONS_ID_MAP.clear();
|
||||
|
||||
//全部删除
|
||||
fileBatchProcessRequest = new FileBatchProcessRequest();
|
||||
fileBatchProcessRequest.setSelectAll(true);
|
||||
fileBatchProcessRequest.setProjectId(project.getId());
|
||||
fileBatchProcessRequest.setExcludeIds(new ArrayList<>() {{
|
||||
this.add(IDGenerator.nextStr());
|
||||
}});
|
||||
this.requestPostWithOk(FileManagementRequestUtils.URL_FILE_DELETE, fileBatchProcessRequest);
|
||||
FileMetadataExample example = new FileMetadataExample();
|
||||
example.createCriteria().andProjectIdEqualTo(project.getId());
|
||||
Assertions.assertEquals(fileMetadataMapper.countByExample(example), 0);
|
||||
//重新上传,用于后续的测试
|
||||
this.fileUploadTestSuccess();
|
||||
}
|
||||
|
||||
private void fileAssociationControllerDelete() throws Exception {
|
||||
//删除bug-id-4的
|
||||
FileAssociationDeleteRequest deleteRequest = new FileAssociationDeleteRequest();
|
||||
deleteRequest.setAssociationIds(sourceAssociationFileMap.get("sty-file-association-bug-id-4"));
|
||||
deleteRequest.setProjectId(project.getId());
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(FileManagementRequestUtils.URL_FILE_ASSOCIATION_DELETE, deleteRequest);
|
||||
int returnCount = Integer.parseInt(JSON.parseObject(mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData().toString());
|
||||
Assertions.assertEquals(returnCount, sourceAssociationFileMap.get("sty-file-association-bug-id-4").size());
|
||||
//重复删除
|
||||
mvcResult = this.requestPostWithOkAndReturn(FileManagementRequestUtils.URL_FILE_ASSOCIATION_DELETE, deleteRequest);
|
||||
returnCount = Integer.parseInt(JSON.parseObject(mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData().toString());
|
||||
Assertions.assertEquals(returnCount, 0);
|
||||
//参数不合法
|
||||
deleteRequest = new FileAssociationDeleteRequest();
|
||||
deleteRequest.setProjectId(project.getId());
|
||||
deleteRequest.setAssociationIds(null);
|
||||
this.requestPost(FileManagementRequestUtils.URL_FILE_ASSOCIATION_DELETE, deleteRequest).andExpect(status().isBadRequest());
|
||||
deleteRequest.setAssociationIds(new ArrayList<>());
|
||||
this.requestPost(FileManagementRequestUtils.URL_FILE_ASSOCIATION_DELETE, deleteRequest).andExpect(status().isBadRequest());
|
||||
|
||||
deleteRequest = new FileAssociationDeleteRequest();
|
||||
deleteRequest.setAssociationIds(sourceAssociationFileMap.get("sty-file-association-bug-id-4"));
|
||||
this.requestPost(FileManagementRequestUtils.URL_FILE_ASSOCIATION_DELETE, deleteRequest).andExpect(status().isBadRequest());
|
||||
|
||||
|
||||
FileAssociationDeleteRequest permisionRequest = new FileAssociationDeleteRequest();
|
||||
permisionRequest.setAssociationIds(sourceAssociationFileMap.get("sty-file-association-bug-id-4"));
|
||||
permisionRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
this.requestPostPermissionTest(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_UPDATE, FileManagementRequestUtils.URL_FILE_ASSOCIATION_DELETE, permisionRequest);
|
||||
}
|
||||
|
||||
private void fileAssociationControllerPage() throws Exception {
|
||||
//关联过的
|
||||
MvcResult mvcResult = this.requestGetWithOkAndReturn(String.format(FileManagementRequestUtils.URL_FILE_ASSOCIATION_LIST, fileAssociationNewFilesOne));
|
||||
List<FileAssociationResponse> fileAssociationResponseList = JSON.parseArray(JSON.toJSONString(JSON.parseObject(mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()), FileAssociationResponse.class);
|
||||
Assertions.assertEquals(fileAssociationResponseList.size(), 2);//这个文件只关联了id-2和id-3
|
||||
//没有关联过
|
||||
mvcResult = this.requestGetWithOkAndReturn(String.format(FileManagementRequestUtils.URL_FILE_ASSOCIATION_LIST, fileAssociationNewFilesFour));
|
||||
fileAssociationResponseList = JSON.parseArray(JSON.toJSONString(JSON.parseObject(mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()), FileAssociationResponse.class);
|
||||
Assertions.assertEquals(fileAssociationResponseList.size(), 0);
|
||||
//数据不存在
|
||||
this.requestGet(String.format(FileManagementRequestUtils.URL_FILE_ASSOCIATION_LIST, "sty-file-association-bug-id-0")).andExpect(status().is5xxServerError());
|
||||
|
||||
this.requestGetPermissionTest(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ, String.format(FileManagementRequestUtils.URL_FILE_ASSOCIATION_LIST, fileAssociationNewFilesOne));
|
||||
}
|
||||
|
||||
private void fileAssociationControllerUpgrade() throws Exception {
|
||||
String associationId = sourceAssociationFileMap.get("sty-file-association-bug-id-2").get(0);
|
||||
MvcResult mvcResult = this.requestGetWithOkAndReturn(String.format(FileManagementRequestUtils.URL_FILE_ASSOCIATION_UPGRADE, project.getId(), associationId));
|
||||
String fileId = JSON.parseObject(mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData().toString();
|
||||
FileMetadataExample example = new FileMetadataExample();
|
||||
example.createCriteria().andIdEqualTo(fileId).andLatestEqualTo(true);
|
||||
Assertions.assertEquals(fileMetadataMapper.countByExample(example), 1);
|
||||
|
||||
//重复更新
|
||||
mvcResult = this.requestGetWithOkAndReturn(String.format(FileManagementRequestUtils.URL_FILE_ASSOCIATION_UPGRADE, project.getId(), associationId));
|
||||
String newFileId = JSON.parseObject(mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData().toString();
|
||||
Assertions.assertEquals(newFileId, fileId);
|
||||
|
||||
this.requestGetPermissionTest(PermissionConstants.PROJECT_FILE_MANAGEMENT_READ_UPDATE, String.format(FileManagementRequestUtils.URL_FILE_ASSOCIATION_UPGRADE, DEFAULT_PROJECT_ID, associationId));
|
||||
}
|
||||
|
||||
|
||||
private void saveSourceAssociationId(String sourceId, List<String> associationIdList) {
|
||||
if (CollectionUtils.isEmpty(associationIdList)) {
|
||||
return;
|
||||
}
|
||||
if (sourceAssociationFileMap.containsKey(sourceId)) {
|
||||
sourceAssociationFileMap.get(sourceId).addAll(associationIdList);
|
||||
sourceAssociationFileMap.get(sourceId).stream().distinct().collect(Collectors.toList());
|
||||
} else {
|
||||
sourceAssociationFileMap.put(sourceId, associationIdList);
|
||||
}
|
||||
}
|
||||
|
||||
public void associationFile() {
|
||||
//关联id-1和id-3 (不覆盖)
|
||||
List<String> fileIdList = new ArrayList<>() {{
|
||||
this.add(fileAssociationNewFileId);
|
||||
this.add(fileAssociationNewFilesOne);
|
||||
}};
|
||||
FileLogRecord fileLogRecord = FileLogRecord.builder()
|
||||
.logModule(OperationLogModule.PROJECT_FILE_MANAGEMENT)
|
||||
.requestMethod(HttpMethodConstants.POST.name())
|
||||
.requestUrl("/project/file/association/test")
|
||||
.operator("admin")
|
||||
.projectId(project.getId())
|
||||
.build();
|
||||
List<String> associationIdList = fileAssociationService.association("sty-file-association-bug-id-3", FileAssociationSourceUtil.SOURCE_TYPE_BUG, fileIdList, false, fileLogRecord);
|
||||
this.checkFileAssociation("sty-file-association-bug-id-3", fileIdList, new ArrayList<>() {{
|
||||
this.add(fileAssociationOldFileId);
|
||||
}});
|
||||
this.saveSourceAssociationId("sty-file-association-bug-id-3", associationIdList);
|
||||
//关联id-3 (覆盖)
|
||||
associationIdList = fileAssociationService.association("sty-file-association-bug-id-3", FileAssociationSourceUtil.SOURCE_TYPE_BUG, fileIdList, true, fileLogRecord);
|
||||
this.checkFileAssociation("sty-file-association-bug-id-3", fileIdList, null);
|
||||
this.saveSourceAssociationId("sty-file-association-bug-id-3", associationIdList);
|
||||
//重新关联(检查是否会重复插入数据)
|
||||
associationIdList = fileAssociationService.association("sty-file-association-bug-id-3", FileAssociationSourceUtil.SOURCE_TYPE_BUG, fileIdList, true, fileLogRecord);
|
||||
this.checkFileAssociation("sty-file-association-bug-id-3", fileIdList, null);
|
||||
this.saveSourceAssociationId("sty-file-association-bug-id-3", associationIdList);
|
||||
//关联id-2 关联所有正常文件
|
||||
List<String> bug2IdList = new ArrayList<>() {{
|
||||
this.add(fileAssociationNewFilesOne);
|
||||
this.add(fileAssociationNewFilesTwo);
|
||||
this.add(fileAssociationNewFilesThree);
|
||||
}};
|
||||
associationIdList = fileAssociationService.association("sty-file-association-bug-id-2", FileAssociationSourceUtil.SOURCE_TYPE_BUG, bug2IdList, true, fileLogRecord);
|
||||
this.checkFileAssociation("sty-file-association-bug-id-2", bug2IdList, null);
|
||||
this.saveSourceAssociationId("sty-file-association-bug-id-2", associationIdList);
|
||||
|
||||
//反例:
|
||||
// 文件参数为空
|
||||
boolean error = false;
|
||||
try {
|
||||
fileAssociationService.association("sty-file-association-bug-id-3", FileAssociationSourceUtil.SOURCE_TYPE_BUG, null, true, fileLogRecord);
|
||||
} catch (Exception e) {
|
||||
error = true;
|
||||
}
|
||||
Assertions.assertTrue(error);
|
||||
error = false;
|
||||
try {
|
||||
fileAssociationService.association("sty-file-association-bug-id-3", FileAssociationSourceUtil.SOURCE_TYPE_BUG, new ArrayList<>(), true, fileLogRecord);
|
||||
} catch (Exception e) {
|
||||
error = true;
|
||||
}
|
||||
Assertions.assertTrue(error);
|
||||
//资源不存在
|
||||
error = false;
|
||||
try {
|
||||
fileAssociationService.association("sty-file-association-bug-id-3", FileAssociationSourceUtil.SOURCE_TYPE_BUG, new ArrayList<>() {{
|
||||
|
||||
}}, true, fileLogRecord);
|
||||
} catch (Exception e) {
|
||||
error = true;
|
||||
}
|
||||
Assertions.assertTrue(error);
|
||||
//文件数量对不上(含有不存在的文件ID)
|
||||
error = false;
|
||||
fileIdList.add(IDGenerator.nextStr());
|
||||
try {
|
||||
fileAssociationService.association("sty-file-association-bug-id-3", FileAssociationSourceUtil.SOURCE_TYPE_BUG, fileIdList, true, fileLogRecord);
|
||||
} catch (Exception e) {
|
||||
error = true;
|
||||
}
|
||||
Assertions.assertTrue(error);
|
||||
}
|
||||
|
||||
public void associationUpgrade() {
|
||||
FileLogRecord fileLogRecord = FileLogRecord.builder()
|
||||
.logModule(OperationLogModule.PROJECT_FILE_MANAGEMENT)
|
||||
.requestMethod(HttpMethodConstants.POST.name())
|
||||
.requestUrl("/project/file/association/upgrade-test")
|
||||
.operator("admin")
|
||||
.projectId(project.getId())
|
||||
.build();
|
||||
|
||||
FileAssociationExample example = new FileAssociationExample();
|
||||
example.createCriteria().andFileIdEqualTo(fileAssociationOldFileId).andSourceIdEqualTo("sty-file-association-bug-id-4");
|
||||
FileAssociation upgradeFileAssociation = fileAssociationMapper.selectByExample(example).get(0);
|
||||
Assertions.assertTrue(sourceAssociationFileMap.get("sty-file-association-bug-id-4").contains(upgradeFileAssociation.getId()));
|
||||
//当前文件不是最新的
|
||||
fileAssociationService.upgrade(upgradeFileAssociation.getId(), fileLogRecord);
|
||||
FileAssociation newAssociation1 = fileAssociationMapper.selectByPrimaryKey(upgradeFileAssociation.getId());
|
||||
Assertions.assertEquals(newAssociation1.getFileId(), fileAssociationNewFileId);
|
||||
|
||||
//当前文件是最新的
|
||||
fileAssociationService.upgrade(upgradeFileAssociation.getId(), fileLogRecord);
|
||||
FileAssociation newAssociation2 = fileAssociationMapper.selectByPrimaryKey(upgradeFileAssociation.getId());
|
||||
Assertions.assertEquals(newAssociation1.getFileId(), newAssociation2.getFileId());
|
||||
|
||||
|
||||
//关联ID不存在
|
||||
boolean error = false;
|
||||
try {
|
||||
fileAssociationService.upgrade(IDGenerator.nextStr(), fileLogRecord);
|
||||
} catch (Exception e) {
|
||||
error = true;
|
||||
}
|
||||
Assertions.assertTrue(error);
|
||||
|
||||
//使用bug-id-2测试: 1.关联表中的文件ID不存在
|
||||
example.clear();
|
||||
example.createCriteria().andFileIdEqualTo(fileAssociationOldFileId).andSourceIdEqualTo("sty-file-association-bug-id-2");
|
||||
FileAssociation upgrade2 = fileAssociationMapper.selectByExample(example).get(0);
|
||||
//先把文件id改成别的,测试完成改回来
|
||||
String originalFileId = upgrade2.getFileId();
|
||||
String originalRefId = upgrade2.getFileRefId();
|
||||
upgrade2.setFileId(IDGenerator.nextStr());
|
||||
upgrade2.setFileRefId(upgrade2.getFileId());
|
||||
fileAssociationMapper.updateByPrimaryKeySelective(upgrade2);
|
||||
error = false;
|
||||
try {
|
||||
fileAssociationService.upgrade(upgrade2.getId(), fileLogRecord);
|
||||
} catch (Exception e) {
|
||||
error = true;
|
||||
}
|
||||
Assertions.assertTrue(error);
|
||||
upgrade2.setFileId(originalFileId);
|
||||
upgrade2.setFileRefId(originalRefId);
|
||||
fileAssociationMapper.updateByPrimaryKeySelective(upgrade2);
|
||||
|
||||
//使用bug-id-2测试: 脏数据->refId找不到最新文件
|
||||
FileMetadata updateMetadata = new FileMetadata();
|
||||
updateMetadata.setId(fileAssociationNewFileId);
|
||||
updateMetadata.setLatest(false);
|
||||
fileMetadataMapper.updateByPrimaryKeySelective(updateMetadata);
|
||||
error = false;
|
||||
try {
|
||||
fileAssociationService.upgrade(upgrade2.getId(), fileLogRecord);
|
||||
} catch (Exception e) {
|
||||
error = true;
|
||||
}
|
||||
Assertions.assertTrue(error);
|
||||
updateMetadata.setLatest(true);
|
||||
fileMetadataMapper.updateByPrimaryKeySelective(updateMetadata);
|
||||
}
|
||||
|
||||
public void transferAndAssociation() throws Exception {
|
||||
FileLogRecord fileLogRecord = FileLogRecord.builder()
|
||||
.logModule(OperationLogModule.PROJECT_FILE_MANAGEMENT)
|
||||
.requestMethod(HttpMethodConstants.POST.name())
|
||||
.requestUrl("/project/file/association/transferAndAssociation-test")
|
||||
.operator("admin")
|
||||
.projectId(project.getId())
|
||||
.build();
|
||||
//关联正常文件
|
||||
String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/file_upload.JPG")).getPath();
|
||||
String fileID = fileAssociationService.transferAndAssociation("testTransferFile.jpg", TempFileUtils.getFile(filePath), "sty-file-association-bug-id-4", FileAssociationSourceUtil.SOURCE_TYPE_BUG, fileLogRecord);
|
||||
FileMetadataExample example = new FileMetadataExample();
|
||||
example.createCriteria().andIdEqualTo(fileID).andNameEqualTo("testTransferFile").andTypeEqualTo("JPG");
|
||||
Assertions.assertEquals(fileMetadataMapper.countByExample(example), 1);
|
||||
//重复转存检查文件名是否加1
|
||||
fileID = fileAssociationService.transferAndAssociation("testTransferFile.jpg", TempFileUtils.getFile(filePath), "sty-file-association-bug-id-4", FileAssociationSourceUtil.SOURCE_TYPE_BUG, fileLogRecord);
|
||||
example.clear();
|
||||
example.createCriteria().andIdEqualTo(fileID).andNameEqualTo("testTransferFile(1)").andTypeEqualTo("JPG");
|
||||
|
||||
Assertions.assertEquals(fileMetadataMapper.countByExample(example), 1);
|
||||
//重复转存检查文件名是否加1
|
||||
fileID = fileAssociationService.transferAndAssociation("testTransferFile.jpg", TempFileUtils.getFile(filePath), "sty-file-association-bug-id-4", FileAssociationSourceUtil.SOURCE_TYPE_BUG, fileLogRecord);
|
||||
example.clear();
|
||||
example.createCriteria().andIdEqualTo(fileID).andNameEqualTo("testTransferFile(2)").andTypeEqualTo("JPG");
|
||||
|
||||
Assertions.assertEquals(fileMetadataMapper.countByExample(example), 1);
|
||||
//测试没有后缀的文件名
|
||||
fileID = fileAssociationService.transferAndAssociation("testTransfer", TempFileUtils.getFile(filePath), "sty-file-association-bug-id-4", FileAssociationSourceUtil.SOURCE_TYPE_BUG, fileLogRecord);
|
||||
example.clear();
|
||||
example.createCriteria().andIdEqualTo(fileID).andNameEqualTo("testTransfer");
|
||||
Assertions.assertEquals(fileMetadataMapper.countByExample(example), 1);
|
||||
//资源不存在
|
||||
boolean error = false;
|
||||
try {
|
||||
fileAssociationService.transferAndAssociation("testTransferFile.jpg", TempFileUtils.getFile(filePath), IDGenerator.nextStr(), FileAssociationSourceUtil.SOURCE_TYPE_BUG, fileLogRecord);
|
||||
} catch (Exception e) {
|
||||
error = true;
|
||||
}
|
||||
Assertions.assertTrue(error);
|
||||
//文件名称不合法
|
||||
error = false;
|
||||
try {
|
||||
fileAssociationService.transferAndAssociation("testTransfer/File.jpg", TempFileUtils.getFile(filePath), IDGenerator.nextStr(), FileAssociationSourceUtil.SOURCE_TYPE_BUG, fileLogRecord);
|
||||
} catch (Exception e) {
|
||||
error = true;
|
||||
}
|
||||
Assertions.assertTrue(error);
|
||||
}
|
||||
|
||||
public void associationDelete() {
|
||||
FileLogRecord fileLogRecord = FileLogRecord.builder()
|
||||
.logModule(OperationLogModule.PROJECT_FILE_MANAGEMENT)
|
||||
.requestMethod(HttpMethodConstants.POST.name())
|
||||
.requestUrl("/project/file/association/delete-test")
|
||||
.operator("admin")
|
||||
.projectId(project.getId())
|
||||
.build();
|
||||
|
||||
//1.正常删除 资源为bug-1
|
||||
FileAssociationExample example = new FileAssociationExample();
|
||||
example.clear();
|
||||
example.createCriteria().andSourceIdEqualTo("sty-file-association-bug-id-1");
|
||||
List<FileAssociation> bug1AssociationList = fileAssociationMapper.selectByExample(example);
|
||||
List<String> idList = bug1AssociationList.stream().map(FileAssociation::getId).collect(Collectors.toList());
|
||||
int deleteCount = fileAssociationService.deleteBySourceId(idList, fileLogRecord);
|
||||
Assertions.assertEquals(idList.size(), deleteCount);
|
||||
//2.入参集合为空
|
||||
deleteCount = fileAssociationService.deleteBySourceId(new ArrayList<>(), fileLogRecord);
|
||||
Assertions.assertEquals(0, deleteCount);
|
||||
deleteCount = fileAssociationService.deleteBySourceId(null, fileLogRecord);
|
||||
Assertions.assertEquals(0, deleteCount);
|
||||
|
||||
//3.里面包含一条已经文件已经删除了的ID 资源为bug-2
|
||||
example.clear();
|
||||
example.createCriteria().andSourceIdEqualTo("sty-file-association-bug-id-2").andFileIdEqualTo(fileAssociationNewFilesThree);
|
||||
FileAssociation association = fileAssociationMapper.selectByExample(example).get(0);
|
||||
//先把文件id改成别的,测试完成改回来
|
||||
association.setFileId(IDGenerator.nextStr());
|
||||
association.setFileRefId(association.getFileId());
|
||||
fileAssociationMapper.updateByPrimaryKeySelective(association);
|
||||
idList = new ArrayList<>() {{
|
||||
this.add(association.getId());
|
||||
}};
|
||||
fileAssociationService.deleteBySourceId(idList, fileLogRecord);
|
||||
|
||||
//4.入参集合包括1条不存在的关联ID 资源为bug-2
|
||||
example.clear();
|
||||
example.createCriteria().andSourceIdEqualTo("sty-file-association-bug-id-2");
|
||||
List<FileAssociation> bug2AssociationList = fileAssociationMapper.selectByExample(example);
|
||||
idList = bug2AssociationList.stream().map(FileAssociation::getId).collect(Collectors.toList());
|
||||
idList.add(IDGenerator.nextStr());
|
||||
deleteCount = fileAssociationService.deleteBySourceId(idList, fileLogRecord);
|
||||
Assertions.assertEquals(idList.size() - 1, deleteCount);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param sourceId 资源ID
|
||||
* @param fileIdList 关联的文件集合
|
||||
* @param oldFileIds 检查关联的文件中是否有过期文件
|
||||
*/
|
||||
private void checkFileAssociation(String sourceId, List<String> fileIdList, List<String> oldFileIds) {
|
||||
FileAssociationExample example = new FileAssociationExample();
|
||||
example.createCriteria().andSourceIdEqualTo(sourceId).andFileIdIn(fileIdList);
|
||||
long count = fileAssociationMapper.countByExample(example);
|
||||
if (CollectionUtils.isEmpty(oldFileIds)) {
|
||||
Assertions.assertEquals(count, fileIdList.size());
|
||||
} else {
|
||||
Assertions.assertEquals(count, fileIdList.size() - oldFileIds.size());
|
||||
example.clear();
|
||||
example.createCriteria().andSourceIdEqualTo(sourceId).andFileIdIn(oldFileIds);
|
||||
Assertions.assertEquals(fileAssociationMapper.countByExample(example), oldFileIds.size());
|
||||
}
|
||||
}
|
||||
|
||||
private String addFileAssociation(String sourceId, String sourceType, String fileId) {
|
||||
FileAssociation fileAssociation = new FileAssociation();
|
||||
fileAssociation.setId(IDGenerator.nextStr());
|
||||
fileAssociation.setFileId(fileId);
|
||||
fileAssociation.setFileRefId(fileId);
|
||||
fileAssociation.setSourceId(sourceId);
|
||||
fileAssociation.setSourceType(sourceType);
|
||||
fileAssociation.setCreateTime(System.currentTimeMillis());
|
||||
fileAssociation.setCreateUser("admin");
|
||||
fileAssociation.setUpdateTime(System.currentTimeMillis());
|
||||
fileAssociation.setUpdateUser("admin");
|
||||
fileAssociation.setFileVersion(fileId);
|
||||
fileAssociationMapper.insert(fileAssociation);
|
||||
return fileAssociation.getId();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(31)
|
||||
public void upgradeFileAssociationTest() throws Exception {
|
||||
//预备:在fileAssociationTest中已经将【sty-file-association-bug-id-1】的文件关联过过期文件
|
||||
//1.首先测试反例:手动修改过期文件所有的版本latest都为false。测试之后改过来
|
||||
//2.升级id-3的
|
||||
//3.升级id-1的
|
||||
|
||||
//反例:
|
||||
//文件不存在
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(32)
|
||||
public void deleteFileAssociationTest() throws Exception {
|
||||
//删除id-1和id-2的
|
||||
//参数校验:空集合
|
||||
//集合里有个假文件id
|
||||
//id-3里关联的文件数据里删除1条源文件数据
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(40)
|
||||
@Sql(scripts = {"/dml/delete_bug.sql"},
|
||||
config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED),
|
||||
executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
|
||||
public void fileAssociationTestOver() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
80以后是文件、模块的移动和删除
|
||||
*/
|
||||
@Test
|
||||
@Order(80)
|
||||
public void moveTest() throws Exception {
|
||||
|
|
|
@ -41,8 +41,8 @@ public class FileManagementRequestUtils {
|
|||
//文件批量移动(权限判断需要提前上传文件,所以放在了主测试类里)
|
||||
public static final String URL_FILE_BATCH_UPDATE = "/project/file/batch-move";
|
||||
|
||||
/**
|
||||
* 存储库相关路径
|
||||
/*
|
||||
存储库相关路径
|
||||
*/
|
||||
//存储库列表
|
||||
public static final String URL_FILE_REPOSITORY_LIST = "/project/file/repository/list/%s";
|
||||
|
@ -59,4 +59,13 @@ public class FileManagementRequestUtils {
|
|||
//添加文件
|
||||
public static final String URL_FILE_REPOSITORY_FILE_ADD = "/project/file/repository/add-file";
|
||||
public static final String URL_FILE_REPOSITORY_FILE_PULL = "/project/file/repository/pull-file/%s";
|
||||
|
||||
/*
|
||||
文件关联
|
||||
*/
|
||||
public static final String URL_FILE_ASSOCIATION_LIST = "/project/file/association/list/%s";
|
||||
public static final String URL_FILE_ASSOCIATION_UPGRADE = "/project/file/association/upgrade/%s/%s";
|
||||
public static final String URL_FILE_ASSOCIATION_DELETE = "/project/file/association/delete";
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
DELETE
|
||||
from bug
|
||||
WHERE id IN ('sty-file-association-bug-id-1', 'sty-file-association-bug-id-2', 'sty-file-association-bug-id-3',
|
||||
'sty-file-association-bug-id-4');
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,
|
||||
update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tag,
|
||||
platform_bug_id, deleted)
|
||||
VALUES ('sty-file-association-bug-id-1', 100000, 'sty-default-bug-1', 'oasis', 'oasis', 'admin',
|
||||
UNIX_TIMESTAMP() * 1000,
|
||||
'admin',
|
||||
UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, '100001100001', 'bug-template-id',
|
||||
'Local', 'open', 'default-tag', null, 0);
|
||||
|
||||
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,
|
||||
update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tag,
|
||||
platform_bug_id, deleted)
|
||||
VALUES ('sty-file-association-bug-id-2', 100001, 'sty-default-bug-2', 'oasis', 'oasis', 'admin',
|
||||
UNIX_TIMESTAMP() * 1000,
|
||||
'admin',
|
||||
UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, '100001100001', 'bug-template-id',
|
||||
'Local', 'open', 'default-tag', null, 0);
|
||||
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,
|
||||
update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tag,
|
||||
platform_bug_id, deleted)
|
||||
VALUES ('sty-file-association-bug-id-3', 100002, 'sty-default-bug-3', 'oasis', 'oasis', 'admin',
|
||||
UNIX_TIMESTAMP() * 1000,
|
||||
'admin',
|
||||
UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, '100001100001', 'bug-template-id',
|
||||
'Local', 'open', 'default-tag', null, 0);
|
||||
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,
|
||||
update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tag,
|
||||
platform_bug_id, deleted)
|
||||
VALUES ('sty-file-association-bug-id-4', 100003, 'sty-default-bug-4', 'oasis', 'oasis', 'admin',
|
||||
UNIX_TIMESTAMP() * 1000,
|
||||
'admin',
|
||||
UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, '100001100001', 'bug-template-id',
|
||||
'Local', 'open', 'default-tag', null, 0);
|
Loading…
Reference in New Issue