feat(接口测试): 清理接口资源

This commit is contained in:
wxg0103 2024-01-22 19:01:52 +08:00 committed by Craftsman
parent fe94252ee0
commit 036f580204
20 changed files with 442 additions and 1291 deletions

View File

@ -1,129 +0,0 @@
package io.metersphere.api.domain;
import io.metersphere.validation.groups.*;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import lombok.Data;
@Data
public class ApiSyncConfig implements Serializable {
@Schema(description = "", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_sync_config.id.not_blank}", groups = {Updated.class})
@Size(min = 1, max = 50, message = "{api_sync_config.id.length_range}", groups = {Created.class, Updated.class})
private String id;
@Schema(description = "API/CASE 来源fk", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_sync_config.resource_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{api_sync_config.resource_id.length_range}", groups = {Created.class, Updated.class})
private String resourceId;
@Schema(description = "来源类型/API/CASE", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_sync_config.resource_type.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{api_sync_config.resource_type.length_range}", groups = {Created.class, Updated.class})
private String resourceType;
@Schema(description = "是否隐藏")
private Boolean hide;
@Schema(description = "是否通知用例创建人", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{api_sync_config.notify_case_creator.not_blank}", groups = {Created.class})
private Boolean notifyCaseCreator;
@Schema(description = "是否通知场景创建人", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{api_sync_config.notify_scenario_creator.not_blank}", groups = {Created.class})
private Boolean notifyScenarioCreator;
@Schema(description = "是否同步用例", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{api_sync_config.sync_enable.not_blank}", groups = {Created.class})
private Boolean syncEnable;
@Schema(description = "是否发送通知")
private Boolean noticeEnable;
@Schema(description = "同步规则")
private String ruleConfig;
private static final long serialVersionUID = 1L;
public enum Column {
id("id", "id", "VARCHAR", false),
resourceId("resource_id", "resourceId", "VARCHAR", false),
resourceType("resource_type", "resourceType", "VARCHAR", false),
hide("hide", "hide", "BIT", false),
notifyCaseCreator("notify_case_creator", "notifyCaseCreator", "BIT", false),
notifyScenarioCreator("notify_scenario_creator", "notifyScenarioCreator", "BIT", false),
syncEnable("sync_enable", "syncEnable", "BIT", false),
noticeEnable("notice_enable", "noticeEnable", "BIT", false),
ruleConfig("rule_config", "ruleConfig", "LONGVARCHAR", false);
private static final String BEGINNING_DELIMITER = "`";
private static final String ENDING_DELIMITER = "`";
private final String column;
private final boolean isColumnNameDelimited;
private final String javaProperty;
private final String jdbcType;
public String value() {
return this.column;
}
public String getValue() {
return this.column;
}
public String getJavaProperty() {
return this.javaProperty;
}
public String getJdbcType() {
return this.jdbcType;
}
Column(String column, String javaProperty, String jdbcType, boolean isColumnNameDelimited) {
this.column = column;
this.javaProperty = javaProperty;
this.jdbcType = jdbcType;
this.isColumnNameDelimited = isColumnNameDelimited;
}
public String desc() {
return this.getEscapedColumnName() + " DESC";
}
public String asc() {
return this.getEscapedColumnName() + " ASC";
}
public static Column[] excludes(Column ... excludes) {
ArrayList<Column> columns = new ArrayList<>(Arrays.asList(Column.values()));
if (excludes != null && excludes.length > 0) {
columns.removeAll(new ArrayList<>(Arrays.asList(excludes)));
}
return columns.toArray(new Column[]{});
}
public static Column[] all() {
return Column.values();
}
public String getEscapedColumnName() {
if (this.isColumnNameDelimited) {
return new StringBuilder().append(BEGINNING_DELIMITER).append(this.column).append(ENDING_DELIMITER).toString();
} else {
return this.column;
}
}
public String getAliasedEscapedColumnName() {
return this.getEscapedColumnName();
}
}
}

View File

@ -1,710 +0,0 @@
package io.metersphere.api.domain;
import java.util.ArrayList;
import java.util.List;
public class ApiSyncConfigExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public ApiSyncConfigExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(String value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(String value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(String value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(String value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(String value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(String value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdLike(String value) {
addCriterion("id like", value, "id");
return (Criteria) this;
}
public Criteria andIdNotLike(String value) {
addCriterion("id not like", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<String> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<String> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(String value1, String value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(String value1, String value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andResourceIdIsNull() {
addCriterion("resource_id is null");
return (Criteria) this;
}
public Criteria andResourceIdIsNotNull() {
addCriterion("resource_id is not null");
return (Criteria) this;
}
public Criteria andResourceIdEqualTo(String value) {
addCriterion("resource_id =", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotEqualTo(String value) {
addCriterion("resource_id <>", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdGreaterThan(String value) {
addCriterion("resource_id >", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdGreaterThanOrEqualTo(String value) {
addCriterion("resource_id >=", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdLessThan(String value) {
addCriterion("resource_id <", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdLessThanOrEqualTo(String value) {
addCriterion("resource_id <=", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdLike(String value) {
addCriterion("resource_id like", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotLike(String value) {
addCriterion("resource_id not like", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdIn(List<String> values) {
addCriterion("resource_id in", values, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotIn(List<String> values) {
addCriterion("resource_id not in", values, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdBetween(String value1, String value2) {
addCriterion("resource_id between", value1, value2, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotBetween(String value1, String value2) {
addCriterion("resource_id not between", value1, value2, "resourceId");
return (Criteria) this;
}
public Criteria andResourceTypeIsNull() {
addCriterion("resource_type is null");
return (Criteria) this;
}
public Criteria andResourceTypeIsNotNull() {
addCriterion("resource_type is not null");
return (Criteria) this;
}
public Criteria andResourceTypeEqualTo(String value) {
addCriterion("resource_type =", value, "resourceType");
return (Criteria) this;
}
public Criteria andResourceTypeNotEqualTo(String value) {
addCriterion("resource_type <>", value, "resourceType");
return (Criteria) this;
}
public Criteria andResourceTypeGreaterThan(String value) {
addCriterion("resource_type >", value, "resourceType");
return (Criteria) this;
}
public Criteria andResourceTypeGreaterThanOrEqualTo(String value) {
addCriterion("resource_type >=", value, "resourceType");
return (Criteria) this;
}
public Criteria andResourceTypeLessThan(String value) {
addCriterion("resource_type <", value, "resourceType");
return (Criteria) this;
}
public Criteria andResourceTypeLessThanOrEqualTo(String value) {
addCriterion("resource_type <=", value, "resourceType");
return (Criteria) this;
}
public Criteria andResourceTypeLike(String value) {
addCriterion("resource_type like", value, "resourceType");
return (Criteria) this;
}
public Criteria andResourceTypeNotLike(String value) {
addCriterion("resource_type not like", value, "resourceType");
return (Criteria) this;
}
public Criteria andResourceTypeIn(List<String> values) {
addCriterion("resource_type in", values, "resourceType");
return (Criteria) this;
}
public Criteria andResourceTypeNotIn(List<String> values) {
addCriterion("resource_type not in", values, "resourceType");
return (Criteria) this;
}
public Criteria andResourceTypeBetween(String value1, String value2) {
addCriterion("resource_type between", value1, value2, "resourceType");
return (Criteria) this;
}
public Criteria andResourceTypeNotBetween(String value1, String value2) {
addCriterion("resource_type not between", value1, value2, "resourceType");
return (Criteria) this;
}
public Criteria andHideIsNull() {
addCriterion("hide is null");
return (Criteria) this;
}
public Criteria andHideIsNotNull() {
addCriterion("hide is not null");
return (Criteria) this;
}
public Criteria andHideEqualTo(Boolean value) {
addCriterion("hide =", value, "hide");
return (Criteria) this;
}
public Criteria andHideNotEqualTo(Boolean value) {
addCriterion("hide <>", value, "hide");
return (Criteria) this;
}
public Criteria andHideGreaterThan(Boolean value) {
addCriterion("hide >", value, "hide");
return (Criteria) this;
}
public Criteria andHideGreaterThanOrEqualTo(Boolean value) {
addCriterion("hide >=", value, "hide");
return (Criteria) this;
}
public Criteria andHideLessThan(Boolean value) {
addCriterion("hide <", value, "hide");
return (Criteria) this;
}
public Criteria andHideLessThanOrEqualTo(Boolean value) {
addCriterion("hide <=", value, "hide");
return (Criteria) this;
}
public Criteria andHideIn(List<Boolean> values) {
addCriterion("hide in", values, "hide");
return (Criteria) this;
}
public Criteria andHideNotIn(List<Boolean> values) {
addCriterion("hide not in", values, "hide");
return (Criteria) this;
}
public Criteria andHideBetween(Boolean value1, Boolean value2) {
addCriterion("hide between", value1, value2, "hide");
return (Criteria) this;
}
public Criteria andHideNotBetween(Boolean value1, Boolean value2) {
addCriterion("hide not between", value1, value2, "hide");
return (Criteria) this;
}
public Criteria andNotifyCaseCreatorIsNull() {
addCriterion("notify_case_creator is null");
return (Criteria) this;
}
public Criteria andNotifyCaseCreatorIsNotNull() {
addCriterion("notify_case_creator is not null");
return (Criteria) this;
}
public Criteria andNotifyCaseCreatorEqualTo(Boolean value) {
addCriterion("notify_case_creator =", value, "notifyCaseCreator");
return (Criteria) this;
}
public Criteria andNotifyCaseCreatorNotEqualTo(Boolean value) {
addCriterion("notify_case_creator <>", value, "notifyCaseCreator");
return (Criteria) this;
}
public Criteria andNotifyCaseCreatorGreaterThan(Boolean value) {
addCriterion("notify_case_creator >", value, "notifyCaseCreator");
return (Criteria) this;
}
public Criteria andNotifyCaseCreatorGreaterThanOrEqualTo(Boolean value) {
addCriterion("notify_case_creator >=", value, "notifyCaseCreator");
return (Criteria) this;
}
public Criteria andNotifyCaseCreatorLessThan(Boolean value) {
addCriterion("notify_case_creator <", value, "notifyCaseCreator");
return (Criteria) this;
}
public Criteria andNotifyCaseCreatorLessThanOrEqualTo(Boolean value) {
addCriterion("notify_case_creator <=", value, "notifyCaseCreator");
return (Criteria) this;
}
public Criteria andNotifyCaseCreatorIn(List<Boolean> values) {
addCriterion("notify_case_creator in", values, "notifyCaseCreator");
return (Criteria) this;
}
public Criteria andNotifyCaseCreatorNotIn(List<Boolean> values) {
addCriterion("notify_case_creator not in", values, "notifyCaseCreator");
return (Criteria) this;
}
public Criteria andNotifyCaseCreatorBetween(Boolean value1, Boolean value2) {
addCriterion("notify_case_creator between", value1, value2, "notifyCaseCreator");
return (Criteria) this;
}
public Criteria andNotifyCaseCreatorNotBetween(Boolean value1, Boolean value2) {
addCriterion("notify_case_creator not between", value1, value2, "notifyCaseCreator");
return (Criteria) this;
}
public Criteria andNotifyScenarioCreatorIsNull() {
addCriterion("notify_scenario_creator is null");
return (Criteria) this;
}
public Criteria andNotifyScenarioCreatorIsNotNull() {
addCriterion("notify_scenario_creator is not null");
return (Criteria) this;
}
public Criteria andNotifyScenarioCreatorEqualTo(Boolean value) {
addCriterion("notify_scenario_creator =", value, "notifyScenarioCreator");
return (Criteria) this;
}
public Criteria andNotifyScenarioCreatorNotEqualTo(Boolean value) {
addCriterion("notify_scenario_creator <>", value, "notifyScenarioCreator");
return (Criteria) this;
}
public Criteria andNotifyScenarioCreatorGreaterThan(Boolean value) {
addCriterion("notify_scenario_creator >", value, "notifyScenarioCreator");
return (Criteria) this;
}
public Criteria andNotifyScenarioCreatorGreaterThanOrEqualTo(Boolean value) {
addCriterion("notify_scenario_creator >=", value, "notifyScenarioCreator");
return (Criteria) this;
}
public Criteria andNotifyScenarioCreatorLessThan(Boolean value) {
addCriterion("notify_scenario_creator <", value, "notifyScenarioCreator");
return (Criteria) this;
}
public Criteria andNotifyScenarioCreatorLessThanOrEqualTo(Boolean value) {
addCriterion("notify_scenario_creator <=", value, "notifyScenarioCreator");
return (Criteria) this;
}
public Criteria andNotifyScenarioCreatorIn(List<Boolean> values) {
addCriterion("notify_scenario_creator in", values, "notifyScenarioCreator");
return (Criteria) this;
}
public Criteria andNotifyScenarioCreatorNotIn(List<Boolean> values) {
addCriterion("notify_scenario_creator not in", values, "notifyScenarioCreator");
return (Criteria) this;
}
public Criteria andNotifyScenarioCreatorBetween(Boolean value1, Boolean value2) {
addCriterion("notify_scenario_creator between", value1, value2, "notifyScenarioCreator");
return (Criteria) this;
}
public Criteria andNotifyScenarioCreatorNotBetween(Boolean value1, Boolean value2) {
addCriterion("notify_scenario_creator not between", value1, value2, "notifyScenarioCreator");
return (Criteria) this;
}
public Criteria andSyncEnableIsNull() {
addCriterion("sync_enable is null");
return (Criteria) this;
}
public Criteria andSyncEnableIsNotNull() {
addCriterion("sync_enable is not null");
return (Criteria) this;
}
public Criteria andSyncEnableEqualTo(Boolean value) {
addCriterion("sync_enable =", value, "syncEnable");
return (Criteria) this;
}
public Criteria andSyncEnableNotEqualTo(Boolean value) {
addCriterion("sync_enable <>", value, "syncEnable");
return (Criteria) this;
}
public Criteria andSyncEnableGreaterThan(Boolean value) {
addCriterion("sync_enable >", value, "syncEnable");
return (Criteria) this;
}
public Criteria andSyncEnableGreaterThanOrEqualTo(Boolean value) {
addCriterion("sync_enable >=", value, "syncEnable");
return (Criteria) this;
}
public Criteria andSyncEnableLessThan(Boolean value) {
addCriterion("sync_enable <", value, "syncEnable");
return (Criteria) this;
}
public Criteria andSyncEnableLessThanOrEqualTo(Boolean value) {
addCriterion("sync_enable <=", value, "syncEnable");
return (Criteria) this;
}
public Criteria andSyncEnableIn(List<Boolean> values) {
addCriterion("sync_enable in", values, "syncEnable");
return (Criteria) this;
}
public Criteria andSyncEnableNotIn(List<Boolean> values) {
addCriterion("sync_enable not in", values, "syncEnable");
return (Criteria) this;
}
public Criteria andSyncEnableBetween(Boolean value1, Boolean value2) {
addCriterion("sync_enable between", value1, value2, "syncEnable");
return (Criteria) this;
}
public Criteria andSyncEnableNotBetween(Boolean value1, Boolean value2) {
addCriterion("sync_enable not between", value1, value2, "syncEnable");
return (Criteria) this;
}
public Criteria andNoticeEnableIsNull() {
addCriterion("notice_enable is null");
return (Criteria) this;
}
public Criteria andNoticeEnableIsNotNull() {
addCriterion("notice_enable is not null");
return (Criteria) this;
}
public Criteria andNoticeEnableEqualTo(Boolean value) {
addCriterion("notice_enable =", value, "noticeEnable");
return (Criteria) this;
}
public Criteria andNoticeEnableNotEqualTo(Boolean value) {
addCriterion("notice_enable <>", value, "noticeEnable");
return (Criteria) this;
}
public Criteria andNoticeEnableGreaterThan(Boolean value) {
addCriterion("notice_enable >", value, "noticeEnable");
return (Criteria) this;
}
public Criteria andNoticeEnableGreaterThanOrEqualTo(Boolean value) {
addCriterion("notice_enable >=", value, "noticeEnable");
return (Criteria) this;
}
public Criteria andNoticeEnableLessThan(Boolean value) {
addCriterion("notice_enable <", value, "noticeEnable");
return (Criteria) this;
}
public Criteria andNoticeEnableLessThanOrEqualTo(Boolean value) {
addCriterion("notice_enable <=", value, "noticeEnable");
return (Criteria) this;
}
public Criteria andNoticeEnableIn(List<Boolean> values) {
addCriterion("notice_enable in", values, "noticeEnable");
return (Criteria) this;
}
public Criteria andNoticeEnableNotIn(List<Boolean> values) {
addCriterion("notice_enable not in", values, "noticeEnable");
return (Criteria) this;
}
public Criteria andNoticeEnableBetween(Boolean value1, Boolean value2) {
addCriterion("notice_enable between", value1, value2, "noticeEnable");
return (Criteria) this;
}
public Criteria andNoticeEnableNotBetween(Boolean value1, Boolean value2) {
addCriterion("notice_enable not between", value1, value2, "noticeEnable");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}

View File

@ -1,40 +0,0 @@
package io.metersphere.api.mapper;
import io.metersphere.api.domain.ApiSyncConfig;
import io.metersphere.api.domain.ApiSyncConfigExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface ApiSyncConfigMapper {
long countByExample(ApiSyncConfigExample example);
int deleteByExample(ApiSyncConfigExample example);
int deleteByPrimaryKey(String id);
int insert(ApiSyncConfig record);
int insertSelective(ApiSyncConfig record);
List<ApiSyncConfig> selectByExampleWithBLOBs(ApiSyncConfigExample example);
List<ApiSyncConfig> selectByExample(ApiSyncConfigExample example);
ApiSyncConfig selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") ApiSyncConfig record, @Param("example") ApiSyncConfigExample example);
int updateByExampleWithBLOBs(@Param("record") ApiSyncConfig record, @Param("example") ApiSyncConfigExample example);
int updateByExample(@Param("record") ApiSyncConfig record, @Param("example") ApiSyncConfigExample example);
int updateByPrimaryKeySelective(ApiSyncConfig record);
int updateByPrimaryKeyWithBLOBs(ApiSyncConfig record);
int updateByPrimaryKey(ApiSyncConfig record);
int batchInsert(@Param("list") List<ApiSyncConfig> list);
int batchInsertSelective(@Param("list") List<ApiSyncConfig> list, @Param("selective") ApiSyncConfig.Column ... selective);
}

View File

@ -1,377 +0,0 @@
<?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.api.mapper.ApiSyncConfigMapper">
<resultMap id="BaseResultMap" type="io.metersphere.api.domain.ApiSyncConfig">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="resource_id" jdbcType="VARCHAR" property="resourceId" />
<result column="resource_type" jdbcType="VARCHAR" property="resourceType" />
<result column="hide" jdbcType="BIT" property="hide" />
<result column="notify_case_creator" jdbcType="BIT" property="notifyCaseCreator" />
<result column="notify_scenario_creator" jdbcType="BIT" property="notifyScenarioCreator" />
<result column="sync_enable" jdbcType="BIT" property="syncEnable" />
<result column="notice_enable" jdbcType="BIT" property="noticeEnable" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.api.domain.ApiSyncConfig">
<result column="rule_config" jdbcType="LONGVARCHAR" property="ruleConfig" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, resource_id, resource_type, hide, notify_case_creator, notify_scenario_creator,
sync_enable, notice_enable
</sql>
<sql id="Blob_Column_List">
rule_config
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.api.domain.ApiSyncConfigExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from api_sync_config
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByExample" parameterType="io.metersphere.api.domain.ApiSyncConfigExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from api_sync_config
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from api_sync_config
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from api_sync_config
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.api.domain.ApiSyncConfigExample">
delete from api_sync_config
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.api.domain.ApiSyncConfig">
insert into api_sync_config (id, resource_id, resource_type,
hide, notify_case_creator, notify_scenario_creator,
sync_enable, notice_enable, rule_config
)
values (#{id,jdbcType=VARCHAR}, #{resourceId,jdbcType=VARCHAR}, #{resourceType,jdbcType=VARCHAR},
#{hide,jdbcType=BIT}, #{notifyCaseCreator,jdbcType=BIT}, #{notifyScenarioCreator,jdbcType=BIT},
#{syncEnable,jdbcType=BIT}, #{noticeEnable,jdbcType=BIT}, #{ruleConfig,jdbcType=LONGVARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.api.domain.ApiSyncConfig">
insert into api_sync_config
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="resourceId != null">
resource_id,
</if>
<if test="resourceType != null">
resource_type,
</if>
<if test="hide != null">
hide,
</if>
<if test="notifyCaseCreator != null">
notify_case_creator,
</if>
<if test="notifyScenarioCreator != null">
notify_scenario_creator,
</if>
<if test="syncEnable != null">
sync_enable,
</if>
<if test="noticeEnable != null">
notice_enable,
</if>
<if test="ruleConfig != null">
rule_config,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="resourceId != null">
#{resourceId,jdbcType=VARCHAR},
</if>
<if test="resourceType != null">
#{resourceType,jdbcType=VARCHAR},
</if>
<if test="hide != null">
#{hide,jdbcType=BIT},
</if>
<if test="notifyCaseCreator != null">
#{notifyCaseCreator,jdbcType=BIT},
</if>
<if test="notifyScenarioCreator != null">
#{notifyScenarioCreator,jdbcType=BIT},
</if>
<if test="syncEnable != null">
#{syncEnable,jdbcType=BIT},
</if>
<if test="noticeEnable != null">
#{noticeEnable,jdbcType=BIT},
</if>
<if test="ruleConfig != null">
#{ruleConfig,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.api.domain.ApiSyncConfigExample" resultType="java.lang.Long">
select count(*) from api_sync_config
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update api_sync_config
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.resourceId != null">
resource_id = #{record.resourceId,jdbcType=VARCHAR},
</if>
<if test="record.resourceType != null">
resource_type = #{record.resourceType,jdbcType=VARCHAR},
</if>
<if test="record.hide != null">
hide = #{record.hide,jdbcType=BIT},
</if>
<if test="record.notifyCaseCreator != null">
notify_case_creator = #{record.notifyCaseCreator,jdbcType=BIT},
</if>
<if test="record.notifyScenarioCreator != null">
notify_scenario_creator = #{record.notifyScenarioCreator,jdbcType=BIT},
</if>
<if test="record.syncEnable != null">
sync_enable = #{record.syncEnable,jdbcType=BIT},
</if>
<if test="record.noticeEnable != null">
notice_enable = #{record.noticeEnable,jdbcType=BIT},
</if>
<if test="record.ruleConfig != null">
rule_config = #{record.ruleConfig,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update api_sync_config
set id = #{record.id,jdbcType=VARCHAR},
resource_id = #{record.resourceId,jdbcType=VARCHAR},
resource_type = #{record.resourceType,jdbcType=VARCHAR},
hide = #{record.hide,jdbcType=BIT},
notify_case_creator = #{record.notifyCaseCreator,jdbcType=BIT},
notify_scenario_creator = #{record.notifyScenarioCreator,jdbcType=BIT},
sync_enable = #{record.syncEnable,jdbcType=BIT},
notice_enable = #{record.noticeEnable,jdbcType=BIT},
rule_config = #{record.ruleConfig,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update api_sync_config
set id = #{record.id,jdbcType=VARCHAR},
resource_id = #{record.resourceId,jdbcType=VARCHAR},
resource_type = #{record.resourceType,jdbcType=VARCHAR},
hide = #{record.hide,jdbcType=BIT},
notify_case_creator = #{record.notifyCaseCreator,jdbcType=BIT},
notify_scenario_creator = #{record.notifyScenarioCreator,jdbcType=BIT},
sync_enable = #{record.syncEnable,jdbcType=BIT},
notice_enable = #{record.noticeEnable,jdbcType=BIT}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.api.domain.ApiSyncConfig">
update api_sync_config
<set>
<if test="resourceId != null">
resource_id = #{resourceId,jdbcType=VARCHAR},
</if>
<if test="resourceType != null">
resource_type = #{resourceType,jdbcType=VARCHAR},
</if>
<if test="hide != null">
hide = #{hide,jdbcType=BIT},
</if>
<if test="notifyCaseCreator != null">
notify_case_creator = #{notifyCaseCreator,jdbcType=BIT},
</if>
<if test="notifyScenarioCreator != null">
notify_scenario_creator = #{notifyScenarioCreator,jdbcType=BIT},
</if>
<if test="syncEnable != null">
sync_enable = #{syncEnable,jdbcType=BIT},
</if>
<if test="noticeEnable != null">
notice_enable = #{noticeEnable,jdbcType=BIT},
</if>
<if test="ruleConfig != null">
rule_config = #{ruleConfig,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.api.domain.ApiSyncConfig">
update api_sync_config
set resource_id = #{resourceId,jdbcType=VARCHAR},
resource_type = #{resourceType,jdbcType=VARCHAR},
hide = #{hide,jdbcType=BIT},
notify_case_creator = #{notifyCaseCreator,jdbcType=BIT},
notify_scenario_creator = #{notifyScenarioCreator,jdbcType=BIT},
sync_enable = #{syncEnable,jdbcType=BIT},
notice_enable = #{noticeEnable,jdbcType=BIT},
rule_config = #{ruleConfig,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.api.domain.ApiSyncConfig">
update api_sync_config
set resource_id = #{resourceId,jdbcType=VARCHAR},
resource_type = #{resourceType,jdbcType=VARCHAR},
hide = #{hide,jdbcType=BIT},
notify_case_creator = #{notifyCaseCreator,jdbcType=BIT},
notify_scenario_creator = #{notifyScenarioCreator,jdbcType=BIT},
sync_enable = #{syncEnable,jdbcType=BIT},
notice_enable = #{noticeEnable,jdbcType=BIT}
where id = #{id,jdbcType=VARCHAR}
</update>
<insert id="batchInsert" parameterType="map">
insert into api_sync_config
(id, resource_id, resource_type, hide, notify_case_creator, notify_scenario_creator,
sync_enable, notice_enable, rule_config)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.resourceId,jdbcType=VARCHAR}, #{item.resourceType,jdbcType=VARCHAR},
#{item.hide,jdbcType=BIT}, #{item.notifyCaseCreator,jdbcType=BIT}, #{item.notifyScenarioCreator,jdbcType=BIT},
#{item.syncEnable,jdbcType=BIT}, #{item.noticeEnable,jdbcType=BIT}, #{item.ruleConfig,jdbcType=LONGVARCHAR}
)
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
insert into api_sync_config (
<foreach collection="selective" item="column" separator=",">
${column.escapedColumnName}
</foreach>
)
values
<foreach collection="list" item="item" separator=",">
(
<foreach collection="selective" item="column" separator=",">
<if test="'id'.toString() == column.value">
#{item.id,jdbcType=VARCHAR}
</if>
<if test="'resource_id'.toString() == column.value">
#{item.resourceId,jdbcType=VARCHAR}
</if>
<if test="'resource_type'.toString() == column.value">
#{item.resourceType,jdbcType=VARCHAR}
</if>
<if test="'hide'.toString() == column.value">
#{item.hide,jdbcType=BIT}
</if>
<if test="'notify_case_creator'.toString() == column.value">
#{item.notifyCaseCreator,jdbcType=BIT}
</if>
<if test="'notify_scenario_creator'.toString() == column.value">
#{item.notifyScenarioCreator,jdbcType=BIT}
</if>
<if test="'sync_enable'.toString() == column.value">
#{item.syncEnable,jdbcType=BIT}
</if>
<if test="'notice_enable'.toString() == column.value">
#{item.noticeEnable,jdbcType=BIT}
</if>
<if test="'rule_config'.toString() == column.value">
#{item.ruleConfig,jdbcType=LONGVARCHAR}
</if>
</foreach>
)
</foreach>
</insert>
</mapper>

View File

@ -437,23 +437,6 @@ CREATE TABLE IF NOT EXISTS api_scenario_report_log(
CREATE INDEX idx_report_id ON api_scenario_report_log(report_id);
CREATE TABLE IF NOT EXISTS api_sync_config(
`id` VARCHAR(50) NOT NULL COMMENT '' ,
`resource_id` VARCHAR(50) NOT NULL COMMENT 'API/CASE 来源fk' ,
`resource_type` VARCHAR(50) NOT NULL COMMENT '来源类型/API/CASE' ,
`hide` BIT(1) DEFAULT 0 COMMENT '是否隐藏' ,
`rule_config` LONGTEXT COMMENT '同步规则' ,
`notify_case_creator` BIT(1) NOT NULL DEFAULT 1 COMMENT '是否通知用例创建人' ,
`notify_scenario_creator` BIT(1) NOT NULL DEFAULT 1 COMMENT '是否通知场景创建人' ,
`sync_enable` BIT(1) NOT NULL DEFAULT 0 COMMENT '是否同步用例' ,
`notice_enable` BIT(1) DEFAULT 0 COMMENT '是否发送通知' ,
PRIMARY KEY (id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '接口同步用例配置';
CREATE INDEX idx_resource_id ON api_sync_config(resource_id);
CREATE TABLE IF NOT EXISTS api_test_case
(

View File

@ -3,6 +3,7 @@ package io.metersphere.sdk.util;
import org.apache.commons.lang3.StringUtils;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
@ -47,4 +48,32 @@ public class ShareUtil {
}
return date;
}
public static long getCleanDate(String expr) {
LocalDate date = null;
LocalDate localDate = LocalDate.now();
long timeMills = 0;
if (StringUtils.isNotBlank(expr)) {
try {
String unit = expr.substring(expr.length() - 1);
int quantity = Integer.parseInt(expr.substring(0, expr.length() - 1));
if (StringUtils.equals(unit, UNIT_DAY)) {
date = localDate.minusDays(quantity);
} else if (StringUtils.equals(unit, UNIT_MONTH)) {
date = localDate.minusMonths(quantity);
} else if (StringUtils.equals(unit, UNIT_YEAR)) {
date = localDate.minusYears(quantity);
} else {
LogUtils.error("clean up expr parse error. expr : " + expr);
}
} catch (Exception e) {
LogUtils.error(e.getMessage(), e);
LogUtils.error("clean up job. get clean date error.");
}
}
if (date != null) {
timeMills = date.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
return timeMills;
}
}

View File

@ -8,9 +8,12 @@ import io.metersphere.api.dto.definition.ApiReportDTO;
import io.metersphere.api.dto.definition.ApiReportDetailDTO;
import io.metersphere.api.dto.definition.ApiReportPageRequest;
import io.metersphere.api.service.ApiReportShareService;
import io.metersphere.api.service.definition.ApiReportLogService;
import io.metersphere.api.service.definition.ApiReportService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.domain.ShareInfo;
import io.metersphere.system.log.annotation.Log;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.security.CheckOwner;
import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager;
@ -49,6 +52,7 @@ public class ApiReportController {
@Operation(summary = "接口测试-接口报告-用例报告重命名")
@CheckOwner(resourceId = "#id", resourceType = "api_report")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_UPDATE)
@Log(type = OperationLogType.UPDATE, expression = "#msClass.updateLog(#id)", msClass = ApiReportLogService.class)
public void rename(@PathVariable String id, @PathVariable String name) {
apiReportService.rename(id, name, SessionUtils.getUserId());
}
@ -57,6 +61,7 @@ public class ApiReportController {
@Operation(summary = "接口测试-接口报告-用例报告删除")
@CheckOwner(resourceId = "#id", resourceType = "api_report")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_DELETE)
@Log(type = OperationLogType.UPDATE, expression = "#msClass.deleteLog(#id)", msClass = ApiReportLogService.class)
public void delete(@PathVariable String id) {
apiReportService.delete(id, SessionUtils.getUserId());
}
@ -88,7 +93,7 @@ public class ApiReportController {
@GetMapping("/get/detail/{reportId}/{stepId}")
@Operation(summary = "接口测试-接口报告-报告详情获取")
@CheckOwner(resourceId = "#reportId", resourceType = "api_report")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ)
@RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_DEFINITION_CASE_UPDATE}, logical = Logical.OR)
public List<ApiReportDetailDTO> getDetail(@PathVariable String stepId,
@PathVariable String reportId) {
return apiReportService.getDetail(stepId, reportId);

View File

@ -8,9 +8,12 @@ import io.metersphere.api.dto.definition.ApiReportPageRequest;
import io.metersphere.api.dto.scenario.ApiScenarioReportDTO;
import io.metersphere.api.dto.scenario.ApiScenarioReportDetailDTO;
import io.metersphere.api.service.ApiReportShareService;
import io.metersphere.api.service.scenario.ApiScenarioReportLogService;
import io.metersphere.api.service.scenario.ApiScenarioReportService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.domain.ShareInfo;
import io.metersphere.system.log.annotation.Log;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.security.CheckOwner;
import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager;
@ -49,6 +52,7 @@ public class ApiScenarioReportController {
@Operation(summary = "接口测试-接口报告-场景报告重命名")
@CheckOwner(resourceId = "#id", resourceType = "api_scenario_report")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_UPDATE)
@Log(type = OperationLogType.UPDATE, expression = "#msClass.updateLog(#id)", msClass = ApiScenarioReportLogService.class)
public void rename(@PathVariable String id, @PathVariable String name) {
apiScenarioReportService.rename(id, name, SessionUtils.getUserId());
}
@ -57,6 +61,7 @@ public class ApiScenarioReportController {
@Operation(summary = "接口测试-接口报告-场景报告删除")
@CheckOwner(resourceId = "#id", resourceType = "api_scenario_report")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_DELETE)
@Log(type = OperationLogType.UPDATE, expression = "#msClass.deleteLog(#id)", msClass = ApiScenarioReportLogService.class)
public void delete(@PathVariable String id) {
apiScenarioReportService.delete(id, SessionUtils.getUserId());
}
@ -88,7 +93,7 @@ public class ApiScenarioReportController {
@GetMapping("/get/detail/{reportId}/{stepId}")
@Operation(summary = "接口测试-接口报告-报告详情获取")
@CheckOwner(resourceId = "#reportId", resourceType = "api_scenario_report")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ)
@RequiresPermissions(value = {PermissionConstants.PROJECT_API_REPORT_READ, PermissionConstants.PROJECT_API_SCENARIO_UPDATE}, logical = Logical.OR)
public List<ApiScenarioReportDetailDTO> getDetail(@PathVariable String stepId,
@PathVariable String reportId) {
return apiScenarioReportService.getDetail(stepId, reportId);

View File

@ -16,4 +16,11 @@ public interface ExtApiReportMapper {
List<ApiReport> selectApiReportByIds(@Param("ids") List<String> ids, @Param("deleted") boolean deleted);
List<ApiReportStepDTO> selectStepsByReportId(String id);
List<String> selectApiReportByProjectId(String projectId);
List<String> selectApiReportByProjectIdAndTime(@Param("time") long time, @Param("projectId") String projectId);
int selectApiReportByTime(@Param("time") long time, @Param("projectId") String projectId);
}

View File

@ -72,6 +72,31 @@
and api_report_detail.report_id = api_report_step.report_id
where api_report_step.report_id = #{reportId}
</select>
<select id="selectApiReportByProjectId" resultType="java.lang.String">
select
api_report.id
from api_report
where api_report.project_id = #{projectId}
limit 500
</select>
<select id="selectApiReportByTime" resultType="java.lang.Integer">
select
count(api_report.id)
from api_report inner join api_report_step on
api_report_step.report_id = api_report.id
where api_report.test_plan_id = 'NONE'
and api_report.start_time &lt;= #{time}
and api_report.project_id = #{projectId}
</select>
<select id="selectApiReportByProjectIdAndTime" resultType="java.lang.String">
select
api_report.id
from api_report inner join api_report_step on
api_report_step.report_id = api_report.id
where api_report.test_plan_id = 'NONE'
and api_report.start_time &lt;= #{time}
and api_report.project_id = #{projectId} limit 500;
</select>
<sql id="filters">

View File

@ -16,4 +16,12 @@ public interface ExtApiScenarioReportMapper {
List<ApiScenarioReport> selectApiReportByIds(@Param("ids") List<String> ids, @Param("deleted") boolean deleted);
List<ApiScenarioReportStepDTO> selectStepByReportId(@Param("reportId") String reportId);
List<String> selectApiScenarioReportByProjectId(String projectId);
int selectReportByTime(@Param("time") long time, @Param("projectId") String projectId);
int selectScenarioReportByTime(@Param("time") long time, @Param("projectId") String projectId);
List<String> selectApiReportByProjectIdAndTime(@Param("time") long time, @Param("projectId") String projectId);
}

View File

@ -75,6 +75,40 @@
and api_scenario_report_detail.report_id = api_scenario_report_step.report_id
where api_scenario_report_step.report_id = #{reportId}
</select>
<select id="selectapiReportByProjectId" resultType="java.lang.String">
</select>
<select id="selectApiScenarioReportByProjectId" resultType="java.lang.String">
select
api_scenario_report.id
from api_scenario_report where api_scenario_report.project_id = #{projectId} limit 500
</select>
<select id="selectReportByTime" resultType="java.lang.Integer">
select
api_scenario_report.id
from api_scenario_report inner join api_scenario_report_step on
api_scenario_report.id = api_scenario_report_step.report_id
where api_scenario_report.start_time &gt;= #{startTime}
and api_scenario_report.start_time &lt;= #{endTime}
</select>
<select id="selectScenarioReportByTime" resultType="java.lang.Integer">
select
count(api_scenario_report.id)
from api_scenario_report inner join api_scenario_report_step on
api_scenario_report.id = api_scenario_report_step.report_id
where api_scenario_report.test_plan_id = 'NONE'
and api_scenario_report.start_time &lt;= #{time}
and api_scenario_report.project_id = #{projectId}
</select>
<select id="selectApiReportByProjectIdAndTime" resultType="java.lang.String">
select
api_scenario_report.id
from api_scenario_report inner join api_scenario_report_step on
api_scenario_report.id = api_scenario_report_step.report_id
where api_scenario_report.test_plan_id = 'NONE'
and api_scenario_report.start_time &lt;= #{time}
and api_scenario_report.project_id = #{projectId} limit 500
</select>
<sql id="filters">

View File

@ -2,11 +2,22 @@ package io.metersphere.api.service;
import io.metersphere.api.domain.*;
import io.metersphere.api.mapper.*;
import io.metersphere.api.service.schedule.SwaggerUrlImportJob;
import io.metersphere.project.domain.ProjectApplication;
import io.metersphere.project.domain.ProjectApplicationExample;
import io.metersphere.project.mapper.ProjectApplicationMapper;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.OperationLogConstants;
import io.metersphere.sdk.constants.ProjectApplicationType;
import io.metersphere.sdk.domain.ShareInfoExample;
import io.metersphere.sdk.mapper.ShareInfoMapper;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.system.domain.Schedule;
import io.metersphere.system.domain.ScheduleExample;
import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.mapper.ScheduleMapper;
import io.metersphere.system.sechedule.ScheduleService;
import io.metersphere.system.service.CleanupProjectResourceService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
@ -15,6 +26,9 @@ import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.stream.Collectors;
import static io.metersphere.sdk.util.ShareUtil.getCleanDate;
@Component
@Transactional(rollbackFor = Exception.class)
@ -47,6 +61,38 @@ public class CleanupApiResourceService implements CleanupProjectResourceService
private ApiDefinitionMockConfigMapper apiDefinitionMockConfigMapper;
@Resource
private ApiDefinitionMockMapper apiDefinitionMockMapper;
@Resource
private ApiReportMapper apiReportMapper;
@Resource
private ExtApiReportMapper extApiReportMapper;
@Resource
private ApiReportStepMapper apiReportStepMapper;
@Resource
private ApiReportDetailMapper apiReportDetailMapper;
@Resource
private ApiReportLogMapper apiReportLogMapper;
@Resource
private ApiScenarioReportMapper apiScenarioReportMapper;
@Resource
private ExtApiScenarioReportMapper extApiScenarioReportMapper;
@Resource
private ApiScenarioReportStepMapper apiScenarioReportStepMapper;
@Resource
private ApiScenarioReportDetailMapper apiScenarioReportDetailMapper;
@Resource
private ApiScenarioReportLogMapper apiScenarioReportLogMapper;
@Resource
private ScheduleService scheduleService;
@Resource
private ScheduleMapper scheduleMapper;
@Resource
private ShareInfoMapper shareInfoMapper;
@Resource
private ProjectApplicationMapper projectApplicationMapper;
@Resource
private ApiDefinitionSwaggerMapper apiDefinitionSwaggerMapper;
private static final String DEFAULT = "30D";
@Async
@ -58,17 +104,59 @@ public class CleanupApiResourceService implements CleanupProjectResourceService
delScenarioModule(projectId);
//删除接口
delApi(projectId);
//删除场景
//删除执行记录
//删除报告
//删除报告 删除执行记录
deleteReport(projectId);
//删除分享报告的数据
deleteShareUrl(projectId);
//删除定时任务
deleteSchedule(projectId);
}
private void deleteShareUrl(String projectId) {
ShareInfoExample example = new ShareInfoExample();
example.createCriteria().andProjectIdEqualTo(projectId);
shareInfoMapper.deleteByExample(example);
}
@Async
@Override
public void cleanReportResources(String projectId) {
LogUtils.info("清理当前项目[" + projectId + "]相关接口测试报告资源");
//只是删除报告的详情 但是会保存执行历史
ProjectApplicationExample example = new ProjectApplicationExample();
example.createCriteria().andProjectIdEqualTo(projectId).andTypeEqualTo(ProjectApplicationType.API.API_CLEAN_REPORT.name());
List<ProjectApplication> projectApplications = projectApplicationMapper.selectByExample(example);
long timeMills = 0;
if (CollectionUtils.isNotEmpty(projectApplications)) {
String expr = projectApplications.getFirst().getTypeValue();
timeMills = getCleanDate(expr);
} else {
timeMills = getCleanDate(DEFAULT);
}
int apiReportCount = extApiReportMapper.selectApiReportByTime(timeMills, projectId);
while (apiReportCount > 0) {
List<String> ids = extApiReportMapper.selectApiReportByProjectIdAndTime(timeMills, projectId);
ApiReportExample reportExample = new ApiReportExample();
reportExample.createCriteria().andIdIn(ids);
ApiReport report = new ApiReport();
report.setDeleted(true);
apiReportMapper.updateByExampleSelective(report, reportExample);
deleteApiReport(ids);
apiReportCount = extApiReportMapper.selectApiReportByTime(timeMills, projectId);
}
int scenarioReportCount = extApiScenarioReportMapper.selectScenarioReportByTime(timeMills, projectId);
while (scenarioReportCount > 0) {
List<String> ids = extApiScenarioReportMapper.selectApiReportByProjectIdAndTime(timeMills, projectId);
ApiScenarioReportExample reportExample = new ApiScenarioReportExample();
reportExample.createCriteria().andIdIn(ids);
ApiScenarioReport report = new ApiScenarioReport();
report.setDeleted(true);
apiScenarioReportMapper.updateByExampleSelective(report, reportExample);
deleteScenarioReport(ids);
scenarioReportCount = extApiScenarioReportMapper.selectScenarioReportByTime(timeMills, projectId);
}
}
private void delScenarioModule(String projectId) {
@ -86,8 +174,6 @@ public class CleanupApiResourceService implements CleanupProjectResourceService
/**
* 删除接口
* 有可能及联数据没有删干净 需要补充
*
* @param projectId
*/
private void delApi(String projectId) {
List<String> apiIds = extApiDefinitionMapper.selectByProjectId(projectId);
@ -159,4 +245,69 @@ public class CleanupApiResourceService implements CleanupProjectResourceService
apiTestCaseBlobMapper.deleteByExample(blobExample);
}
private void deleteReport(String projectId) {
ApiReportExample reportExample = new ApiReportExample();
reportExample.createCriteria().andProjectIdEqualTo(projectId);
long apiCount = apiReportMapper.countByExample(reportExample);
while (apiCount > 0) {
List<String> ids = extApiReportMapper.selectApiReportByProjectId(projectId);
ApiReportExample example = new ApiReportExample();
example.createCriteria().andIdIn(ids);
apiReportMapper.deleteByExample(example);
deleteApiReport(ids);
apiCount = apiReportMapper.countByExample(reportExample);
}
ApiScenarioReportExample scenarioReportExample = new ApiScenarioReportExample();
scenarioReportExample.createCriteria().andProjectIdEqualTo(projectId);
long scenarioCount = apiScenarioReportMapper.countByExample(scenarioReportExample);
while (scenarioCount > 0) {
List<String> ids = extApiScenarioReportMapper.selectApiScenarioReportByProjectId(projectId);
ApiScenarioReportExample example = new ApiScenarioReportExample();
example.createCriteria().andIdIn(ids);
apiScenarioReportMapper.deleteByExample(example);
deleteScenarioReport(ids);
scenarioCount = apiReportMapper.countByExample(reportExample);
}
}
private void deleteApiReport(List<String> ids) {
ApiReportStepExample stepExample = new ApiReportStepExample();
stepExample.createCriteria().andReportIdIn(ids);
apiReportStepMapper.deleteByExample(stepExample);
ApiReportDetailExample detailExample = new ApiReportDetailExample();
detailExample.createCriteria().andReportIdIn(ids);
apiReportDetailMapper.deleteByExample(detailExample);
ApiReportLogExample logExample = new ApiReportLogExample();
logExample.createCriteria().andReportIdIn(ids);
apiReportLogMapper.deleteByExample(logExample);
}
private void deleteScenarioReport(List<String> ids) {
ApiScenarioReportStepExample stepExample = new ApiScenarioReportStepExample();
stepExample.createCriteria().andReportIdIn(ids);
apiScenarioReportStepMapper.deleteByExample(stepExample);
ApiScenarioReportDetailExample detailExample = new ApiScenarioReportDetailExample();
detailExample.createCriteria().andReportIdIn(ids);
apiScenarioReportDetailMapper.deleteByExample(detailExample);
ApiScenarioReportLogExample logExample = new ApiScenarioReportLogExample();
logExample.createCriteria().andReportIdIn(ids);
apiScenarioReportLogMapper.deleteByExample(logExample);
}
private void deleteSchedule(String projectId) {
ScheduleExample scheduleExample = new ScheduleExample();
scheduleExample.createCriteria().andProjectIdEqualTo(projectId).andJobEqualTo(SwaggerUrlImportJob.class.getName());
List<Schedule> schedules = scheduleMapper.selectByExample(scheduleExample);
if (CollectionUtils.isNotEmpty(schedules)) {
scheduleService.deleteByResourceIds(schedules.stream().map(Schedule::getResourceId).collect(Collectors.toList()), SwaggerUrlImportJob.class.getName());
}
ApiDefinitionSwaggerExample swaggerExample = new ApiDefinitionSwaggerExample();
swaggerExample.createCriteria().andProjectIdEqualTo(projectId);
apiDefinitionSwaggerMapper.deleteByExample(swaggerExample);
//TODO 删除场景的定时任务
}
}

View File

@ -1,6 +1,7 @@
package io.metersphere.api.service.definition;
import io.metersphere.api.domain.ApiReport;
import io.metersphere.api.mapper.ApiReportMapper;
import io.metersphere.api.mapper.ExtApiReportMapper;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
@ -25,9 +26,12 @@ public class ApiReportLogService {
private OperationLogService operationLogService;
@Resource
private ExtApiReportMapper extApiReportMapper;
@Resource
private ApiReportMapper apiReportMapper;
public void deleteLog(ApiReport apiReport) {
public void deleteLog(String id) {
ApiReport apiReport = apiReportMapper.selectByPrimaryKey(id);
Project project = projectMapper.selectByPrimaryKey(apiReport.getProjectId());
LogDTO dto = new LogDTO(
apiReport.getProjectId(),
@ -44,7 +48,8 @@ public class ApiReportLogService {
operationLogService.add(dto);
}
public void updateLog(ApiReport apiReport) {
public void updateLog(String id) {
ApiReport apiReport = apiReportMapper.selectByPrimaryKey(id);
Project project = projectMapper.selectByPrimaryKey(apiReport.getProjectId());
LogDTO dto = new LogDTO(
apiReport.getProjectId(),

View File

@ -99,7 +99,6 @@ public class ApiReportService {
apiReport.setUpdateTime(System.currentTimeMillis());
apiReport.setUpdateUser(userId);
apiReportMapper.updateByPrimaryKeySelective(apiReport);
apiReportLogService.updateLog(apiReport);
}
public void delete(String id, String userId) {
@ -108,7 +107,6 @@ public class ApiReportService {
apiReport.setDeleteTime(System.currentTimeMillis());
apiReport.setDeleteUser(userId);
apiReportMapper.updateByPrimaryKeySelective(apiReport);
apiReportLogService.deleteLog(apiReport);
}
private ApiReport checkResource(String id) {

View File

@ -80,6 +80,7 @@ public class ApiTestCaseLogService {
dto.setPath("/api/case/delete/" + id);
dto.setMethod(HttpMethodConstants.GET.name());
dto.setOriginalValue(JSON.toJSONBytes(apiTestCase));
operationLogService.deleteBySourceIds(List.of(id));
return dto;
}
@ -220,6 +221,7 @@ public class ApiTestCaseLogService {
}
);
operationLogService.batchAdd(logs);
operationLogService.deleteBySourceIds(apiTestCases.stream().map(ApiTestCase::getId).toList());
}
public void batchToGcLog(List<ApiTestCase> apiTestCases, String operator, String projectId) {

View File

@ -1,6 +1,7 @@
package io.metersphere.api.service.scenario;
import io.metersphere.api.domain.ApiScenarioReport;
import io.metersphere.api.mapper.ApiScenarioReportMapper;
import io.metersphere.api.mapper.ExtApiScenarioReportMapper;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
@ -26,15 +27,18 @@ public class ApiScenarioReportLogService {
private OperationLogService operationLogService;
@Resource
private ExtApiScenarioReportMapper extApiScenarioReportMapper;
@Resource
private ApiScenarioReportMapper apiScenarioReportMapper;
public void deleteLog(ApiScenarioReport scenarioReport) {
public void deleteLog(String id) {
ApiScenarioReport scenarioReport = apiScenarioReportMapper.selectByPrimaryKey(id);
Project project = projectMapper.selectByPrimaryKey(scenarioReport.getProjectId());
LogDTO dto = new LogDTO(
scenarioReport.getProjectId(),
project.getOrganizationId(),
scenarioReport.getId(),
scenarioReport.getUpdateUser(),
null,
OperationLogType.DELETE.name(),
OperationLogModule.API_REPORT,
scenarioReport.getName());
@ -45,13 +49,14 @@ public class ApiScenarioReportLogService {
operationLogService.add(dto);
}
public void updateLog(ApiScenarioReport scenarioReport) {
public void updateLog(String id) {
ApiScenarioReport scenarioReport = apiScenarioReportMapper.selectByPrimaryKey(id);
Project project = projectMapper.selectByPrimaryKey(scenarioReport.getProjectId());
LogDTO dto = new LogDTO(
scenarioReport.getProjectId(),
project.getOrganizationId(),
scenarioReport.getId(),
scenarioReport.getUpdateUser(),
null,
OperationLogType.UPDATE.name(),
OperationLogModule.API_REPORT,
scenarioReport.getName());

View File

@ -100,7 +100,6 @@ public class ApiScenarioReportService {
apiScenarioReport.setUpdateTime(System.currentTimeMillis());
apiScenarioReport.setUpdateUser(userId);
apiScenarioReportMapper.updateByPrimaryKeySelective(apiScenarioReport);
apiScenarioReportLogService.updateLog(apiScenarioReport);
}
public void delete(String id, String userId) {
@ -109,7 +108,6 @@ public class ApiScenarioReportService {
scenarioReport.setDeleteTime(System.currentTimeMillis());
scenarioReport.setDeleteUser(userId);
apiScenarioReportMapper.updateByPrimaryKeySelective(scenarioReport);
apiScenarioReportLogService.deleteLog(scenarioReport);
}
private ApiScenarioReport checkResource(String id) {

View File

@ -3,7 +3,18 @@ package io.metersphere.api.controller;
import io.metersphere.api.domain.*;
import io.metersphere.api.mapper.*;
import io.metersphere.api.service.CleanupApiResourceService;
import io.metersphere.api.service.definition.ApiReportService;
import io.metersphere.api.service.scenario.ApiScenarioReportService;
import io.metersphere.api.service.schedule.SwaggerUrlImportJob;
import io.metersphere.project.domain.ProjectApplication;
import io.metersphere.project.mapper.ProjectApplicationMapper;
import io.metersphere.sdk.constants.ApiReportStatus;
import io.metersphere.sdk.constants.ProjectApplicationType;
import io.metersphere.sdk.constants.ScheduleType;
import io.metersphere.system.domain.Schedule;
import io.metersphere.system.invoker.ProjectServiceInvoker;
import io.metersphere.system.mapper.ScheduleMapper;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
@ -13,6 +24,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -31,6 +45,18 @@ public class CleanupApiTests {
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private ApiDefinitionMockMapper apiDefinitionMockMapper;
@Resource
private ApiReportService apiReportService;
@Resource
private ApiScenarioReportService apiScenarioReportService;
@Resource
private ScheduleMapper scheduleMapper;
@Resource
private ProjectApplicationMapper projectApplicationMapper;
@Resource
private ApiReportMapper apiReportMapper;
@Resource
private ApiScenarioReportMapper apiScenarioReportMapper;
@Autowired
public CleanupApiTests(ProjectServiceInvoker serviceInvoker) {
@ -115,8 +141,122 @@ public class CleanupApiTests {
@Order(1)
public void testCleanupResource() throws Exception {
initData();
initReportData("test");
initScheduleData();
serviceInvoker.invokeServices("test");
cleanupApiResourceService.deleteResources("test");
}
private void initScheduleData() {
Schedule schedule = new Schedule();
schedule.setName("test");
schedule.setResourceId("test");
schedule.setEnable(true);
schedule.setValue("test");
schedule.setKey("test");
schedule.setCreateUser("admin");
schedule.setProjectId("test");
schedule.setConfig("config");
schedule.setJob(SwaggerUrlImportJob.class.getName());
schedule.setType(ScheduleType.CRON.name());
schedule.setId(IDGenerator.nextStr());
schedule.setCreateTime(System.currentTimeMillis());
schedule.setUpdateTime(System.currentTimeMillis());
scheduleMapper.insertSelective(schedule);
}
@Test
@Order(2)
public void testCleanupReport() throws Exception {
initReportData("test-clean-project");
cleanupApiResourceService.cleanReportResources("test-clean-project");
ApiReportExample apiReportExample = new ApiReportExample();
apiReportExample.createCriteria().andProjectIdEqualTo("test-clean-project");
apiReportMapper.deleteByExample(apiReportExample);
ApiScenarioReportExample apiScenarioReportExample = new ApiScenarioReportExample();
apiScenarioReportExample.createCriteria().andProjectIdEqualTo("test-clean-project");
apiScenarioReportMapper.deleteByExample(apiScenarioReportExample);
// 清理报告有数据
ProjectApplication projectApplication = new ProjectApplication();
projectApplication.setProjectId("test-clean-project-report");
projectApplication.setType(ProjectApplicationType.API.API_CLEAN_REPORT.name());
projectApplication.setTypeValue("1D");
projectApplicationMapper.insert(projectApplication);
initReportData("test-clean-project1");
cleanupApiResourceService.cleanReportResources("test-clean-project1");
}
private void initReportData(String projectId) {
List<ApiReport> reports = new ArrayList<>();
for (int i = 0; i < 2515; i++) {
ApiReport apiReport = new ApiReport();
apiReport.setId("clean-report-id" + projectId + i);
apiReport.setProjectId(projectId);
apiReport.setName("clean-report-name" + i);
apiReport.setStartTime(1703174400000L);
apiReport.setResourceId("clean-resource-id" + i);
apiReport.setCreateUser("admin");
apiReport.setUpdateUser("admin");
apiReport.setUpdateTime(System.currentTimeMillis());
apiReport.setPoolId("api-pool-id" + i);
apiReport.setEnvironmentId("api-environment-id" + i);
apiReport.setRunMode("api-run-mode" + i);
if (i % 50 == 0) {
apiReport.setStatus(ApiReportStatus.SUCCESS.name());
} else if (i % 39 == 0) {
apiReport.setStatus(ApiReportStatus.ERROR.name());
}
apiReport.setTriggerMode("api-trigger-mode" + i);
apiReport.setVersionId("api-version-id" + i);
reports.add(apiReport);
}
apiReportService.insertApiReport(reports);
List<ApiReportStep> steps = new ArrayList<>();
for (int i = 0; i < 1515; i++) {
ApiReportStep apiReportStep = new ApiReportStep();
apiReportStep.setStepId("clean-api-report-step-id" + projectId + i);
apiReportStep.setReportId("clean-report-id" + projectId + i);
apiReportStep.setSort(0L);
apiReportStep.setStepType("case");
steps.add(apiReportStep);
}
apiReportService.insertApiReportStep(steps);
List<ApiScenarioReport> scenarioReports = new ArrayList<>();
for (int i = 0; i < 2515; i++) {
ApiScenarioReport scenarioReport = new ApiScenarioReport();
scenarioReport.setId("clean-scenario-report-id" + projectId + i);
scenarioReport.setProjectId(projectId);
scenarioReport.setName("clean--scenario-report-name" + i);
scenarioReport.setStartTime(1703174400000L);
scenarioReport.setScenarioId("scenario-scenario-id" + i);
scenarioReport.setCreateUser("admin");
scenarioReport.setUpdateUser("admin");
if (i % 50 == 0) {
scenarioReport.setStatus(ApiReportStatus.SUCCESS.name());
} else if (i % 39 == 0) {
scenarioReport.setStatus(ApiReportStatus.ERROR.name());
}
scenarioReport.setUpdateTime(System.currentTimeMillis());
scenarioReport.setPoolId("api-pool-id" + i);
scenarioReport.setEnvironmentId("api-environment-id" + i);
scenarioReport.setRunMode("api-run-mode" + i);
scenarioReport.setTriggerMode("api-trigger-mode" + i);
scenarioReport.setVersionId("api-version-id" + i);
scenarioReports.add(scenarioReport);
}
apiScenarioReportService.insertApiScenarioReport(scenarioReports);
List<ApiScenarioReportStep> scenarioReportSteps = new ArrayList<>();
for (int i = 0; i < 1515; i++) {
ApiScenarioReportStep apiScenarioReportStep = new ApiScenarioReportStep();
apiScenarioReportStep.setStepId("clean-step-id" + projectId + i);
apiScenarioReportStep.setReportId("clean-scenario-report-id" + projectId + i);
apiScenarioReportStep.setSort(0L);
apiScenarioReportStep.setStepType("case");
scenarioReportSteps.add(apiScenarioReportStep);
}
apiScenarioReportService.insertApiScenarioReportStep(scenarioReportSteps);
}
}

View File

@ -8,6 +8,7 @@ import io.metersphere.sdk.mapper.OperationLogMapper;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.OperationHistory;
import io.metersphere.system.domain.OperationHistoryExample;
import io.metersphere.system.domain.Organization;
import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.log.dto.LogDTO;
@ -58,6 +59,7 @@ public class OperationLogService {
BeanUtils.copyBean(history, log);
return history;
}
private OperationLogBlob getBlob(LogDTO log) {
OperationLogBlob blob = new OperationLogBlob();
blob.setId(log.getId());
@ -140,4 +142,14 @@ public class OperationLogService {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
@Async
public void deleteBySourceIds(List<String> ids) {
if (CollectionUtils.isEmpty(ids)) {
return;
}
OperationHistoryExample example = new OperationHistoryExample();
example.createCriteria().andSourceIdIn(ids);
operationHistoryMapper.deleteByExample(example);
}
}