refactor(项目设置): 重构更新状态定义和状态流接口

This commit is contained in:
AgAngle 2023-11-02 10:28:50 +08:00 committed by jianxing
parent 03109b9bff
commit b2924b1a58
20 changed files with 492 additions and 427 deletions

View File

@ -1,24 +1,36 @@
package io.metersphere.sdk.constants;
import io.metersphere.sdk.util.Translator;
import lombok.Getter;
import java.util.Arrays;
@Getter
public enum BugStatusDefinitionType {
/**
* 起始状态
*/
START("status_definition.type.start"),
START("status_definition.type.start", true),
/**
* 结束状态
*/
END("status_definition.type.end");
END("status_definition.type.end", false);
BugStatusDefinitionType(String name) {
BugStatusDefinitionType(String name, Boolean isSingleChoice) {
this.name = name;
this.isSingleChoice = isSingleChoice;
}
/**
* 状态名
*/
private String name;
/**
* 是否是单选
*/
private Boolean isSingleChoice;
public String getName() {
return Translator.get(name);
public static BugStatusDefinitionType getStatusDefinitionType(String type) {
return Arrays.stream(BugStatusDefinitionType.values()).filter(item -> item.name().equals(type))
.findFirst().orElse(null);
}
}

View File

@ -407,6 +407,7 @@ internal_custom_field_permission_error=系统字段或模板无法删除!
internal_template_permission_error=系统模板无法删除!
default_template_permission_error=默认模板无法删除!
field_validate_error={0}字段参数值不合法
status_definition_required_error=该状态无法取消
#result message
http_result_success=操作成功

View File

@ -410,6 +410,7 @@ internal_custom_field_permission_error=System fields cannot be deleted
internal_template_permission_error=System template cannot be deleted
default_template_permission_error=Default templates cannot be deleted
field_validate_error=The field {0} value is invalid
status_definition_required_error=This status cannot be canceled
#result message
http_result_success=operate success

View File

@ -407,6 +407,7 @@ internal_custom_field_permission_error=系统字段或模板无法删除!
internal_template_permission_error=系统模板无法删除!
default_template_permission_error=默认模板无法删除!
field_validate_error={0}字段参数值不合法
status_definition_required_error=该状态无法取消
#result message
http_result_success=操作成功

View File

@ -406,6 +406,7 @@ internal_custom_field_permission_error=系統字段或模板無法刪除!
internal_template_permission_error=系統模板無法刪除!
default_template_permission_error=默认模板无法删除!
field_validate_error={0}字段參數值不合法
status_definition_required_error=該狀態無法取消
#result message
http_result_success=操作成功

View File

@ -34,7 +34,8 @@ public class ProjectStatusFlowSettingLogService {
public LogDTO updateStatusDefinitionLog(StatusDefinitionUpdateRequest request) {
return updateStatusFlowSettingLog(request.getScopeId(), request.getScene());
StatusItem statusItem = statusItemMapper.selectByPrimaryKey(request.getStatusId());
return updateStatusFlowSettingLog(statusItem.getScopeId(), statusItem.getScene());
}
public LogDTO addStatusItemLog(StatusItemAddRequest request) {
@ -52,7 +53,8 @@ public class ProjectStatusFlowSettingLogService {
}
public LogDTO updateStatusFlowLog(StatusFlowUpdateRequest request) {
return updateStatusFlowSettingLog(request.getScopeId(), request.getScene());
StatusItem statusItem = statusItemMapper.selectByPrimaryKey(request.getFromId());
return updateStatusFlowSettingLog(statusItem.getScopeId(), statusItem.getScene());
}
public LogDTO updateStatusFlowSettingLog(String scopeId, String scene) {

View File

@ -43,11 +43,11 @@ public class ProjectStatusFlowSettingService extends BaseStatusFlowSettingServic
* 比如设置成项目
* @param request
*/
@Override
public void updateStatusDefinition(StatusDefinitionUpdateRequest request) {
ProjectService.checkResourceExist(request.getScopeId());
projectTemplateService.checkProjectTemplateEnable(request.getScopeId(), request.getScene());
super.updateStatusDefinition(request);
StatusItem statusItem = baseStatusItemService.getWithCheck(request.getStatusId());
ProjectService.checkResourceExist(statusItem.getScopeId());
projectTemplateService.checkProjectTemplateEnable(statusItem.getScopeId(), statusItem.getScene());
super.updateStatusDefinition(statusItem, request);
}
/**
@ -105,8 +105,11 @@ public class ProjectStatusFlowSettingService extends BaseStatusFlowSettingServic
* @param request
*/
public void updateStatusFlow(StatusFlowUpdateRequest request) {
ProjectService.checkResourceExist(request.getScopeId());
projectTemplateService.checkProjectTemplateEnable(request.getScopeId(), request.getScene());
StatusItem fromStatusItem = baseStatusItemService.getWithCheck(request.getFromId());
StatusItem toStatusItem = baseStatusItemService.getWithCheck(request.getToId());
ProjectService.checkResourceExist(fromStatusItem.getScopeId());
ProjectService.checkResourceExist(toStatusItem.getScopeId());
projectTemplateService.checkProjectTemplateEnable(fromStatusItem.getScopeId(), fromStatusItem.getScene());
super.updateStatusFlow(request);
}

View File

@ -34,8 +34,7 @@ import java.util.List;
import java.util.stream.Collectors;
import static io.metersphere.project.enums.result.ProjectResultCode.PROJECT_TEMPLATE_PERMISSION;
import static io.metersphere.system.controller.handler.result.CommonResultCode.STATUS_ITEM_EXIST;
import static io.metersphere.system.controller.handler.result.CommonResultCode.STATUS_ITEM_NOT_EXIST;
import static io.metersphere.system.controller.handler.result.CommonResultCode.*;
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
import static io.metersphere.system.controller.result.SystemResultCode.ORGANIZATION_TEMPLATE_PERMISSION;
@ -58,6 +57,7 @@ public class ProjectStatusFlowSettingControllerTest extends BaseTest {
private static final String STATUS_FLOW_UPDATE = "status/flow/update";
private static StatusItem addStatusItem;
private static StatusItem anotherAddStatusItem;
@Resource
private StatusItemMapper statusItemMapper;
@ -124,7 +124,8 @@ public class ProjectStatusFlowSettingControllerTest extends BaseTest {
request.setName("test3");
request.setAllTransferTo(true);
mvcResult = this.requestPostWithOkAndReturn(STATUS_ADD, request);
statusItemId = getResultData(mvcResult, StatusItem.class).getId();
anotherAddStatusItem = getResultData(mvcResult, StatusItem.class);
statusItemId = anotherAddStatusItem.getId();
OrganizationStatusFlowSettingControllerTest.assertAllTransferTo(statusItemId, request.getScopeId());
// @@校验组织是否存在
@ -178,21 +179,41 @@ public class ProjectStatusFlowSettingControllerTest extends BaseTest {
requestPostPermissionTest(PermissionConstants.PROJECT_TEMPLATE_UPDATE, STATUS_UPDATE, request);
}
@Test
@Order(3)
public void updateStatusDefinition() throws Exception {
StatusDefinitionUpdateRequest request = new StatusDefinitionUpdateRequest();
request.setScene(TemplateScene.BUG.name());
request.setScopeId(DEFAULT_PROJECT_ID);
StatusDefinitionUpdateRequest.StatusDefinitionRequest statusDefinition = new StatusDefinitionUpdateRequest.StatusDefinitionRequest();
statusDefinition.setStatusId(addStatusItem.getId());
statusDefinition.setDefinitionId(BugStatusDefinitionType.END.name());
request.setStatusDefinitions(List.of(statusDefinition));
request.setStatusId(addStatusItem.getId());
request.setDefinitionId(BugStatusDefinitionType.END.name());
request.setEnable(true);
// @@校验请求成功
this.requestPostWithOkAndReturn(STATUS_DEFINITION_UPDATE, request);
assertUpdateStatusDefinition(DEFAULT_PROJECT_ID);
OrganizationStatusFlowSettingControllerTest.assertUpdateStatusDefinition(request);
// 校验项目是否同步修改
OrganizationStatusFlowSettingControllerTest.assertRefUpdateStatusDefinition(request);
// 取消关联
request.setEnable(false);
this.requestPostWithOkAndReturn(STATUS_DEFINITION_UPDATE, request);
OrganizationStatusFlowSettingControllerTest.assertUpdateStatusDefinition(request);
// @测试单选
request.setStatusId(addStatusItem.getId());
request.setDefinitionId(BugStatusDefinitionType.START.name());
request.setEnable(true);
this.requestPostWithOkAndReturn(STATUS_DEFINITION_UPDATE, request);
OrganizationStatusFlowSettingControllerTest.assertUpdateStatusDefinition(request);
// 校验单选
OrganizationStatusFlowSettingControllerTest.assertSingleChoiceUpdateStatusDefinition(request);
// 校验单选禁止取消
request.setEnable(false);
assertErrorCode(this.requestPost(STATUS_DEFINITION_UPDATE, request), STATUS_DEFINITION_REQUIRED_ERROR);
// 设置回来避免其他地方校验出错
StatusItem newStatusItem = OrganizationStatusFlowSettingControllerTest.getNewStatusItem(addStatusItem.getScopeId());
request.setStatusId(newStatusItem.getId());
request.setEnable(true);
this.requestPostWithOkAndReturn(STATUS_DEFINITION_UPDATE, request);
// @校验是否开启组织模板
changeOrgTemplateEnable(true);
@ -200,11 +221,7 @@ public class ProjectStatusFlowSettingControllerTest extends BaseTest {
changeOrgTemplateEnable(false);
// @@状态不存在
request.getStatusDefinitions().get(0).setStatusId("1111");
assertErrorCode(this.requestPost(STATUS_DEFINITION_UPDATE, request), STATUS_ITEM_NOT_EXIST);
// @@校验组织是否存在
request.setScopeId("1111");
request.setStatusId("1111");
assertErrorCode(this.requestPost(STATUS_DEFINITION_UPDATE, request), NOT_FOUND);
// @@校验日志
@ -215,34 +232,27 @@ public class ProjectStatusFlowSettingControllerTest extends BaseTest {
requestPostPermissionTest(PermissionConstants.PROJECT_TEMPLATE_UPDATE, STATUS_DEFINITION_UPDATE, request);
}
private void assertUpdateStatusDefinition(String scopeId) {
List<String> statusIds = baseStatusItemService.getByScopeIdAndScene(scopeId, TemplateScene.BUG.name()).stream().map(StatusItem::getId).toList();
List<StatusDefinition> statusDefinitions = baseStatusDefinitionService.getStatusDefinitions(statusIds);
Assertions.assertEquals(statusDefinitions.size(), 1);
Assertions.assertEquals(statusDefinitions.get(0).getDefinitionId(), BugStatusDefinitionType.END.name());
}
@Test
@Order(4)
public void updateStatusFlow() throws Exception {
StatusFlowUpdateRequest request = new StatusFlowUpdateRequest();
request.setScopeId(DEFAULT_PROJECT_ID);
request.setScene(TemplateScene.BUG.name());
request.setFromId(anotherAddStatusItem.getId());
request.setToId(addStatusItem.getId());
StatusFlowUpdateRequest.StatusFlowRequest statusFlow = new StatusFlowUpdateRequest.StatusFlowRequest();
statusFlow.setFromId(addStatusItem.getId());
StatusItemExample example = new StatusItemExample();
example.createCriteria().andScopeIdEqualTo(DEFAULT_PROJECT_ID).andSceneEqualTo(TemplateScene.BUG.name());
StatusItem targetStatusItem = statusItemMapper.selectByExample(example).stream()
.filter(item -> !StringUtils.equals(addStatusItem.getId(), item.getId()))
.findFirst()
.get();
statusFlow.setToId(targetStatusItem.getId());
request.setStatusFlows(List.of(statusFlow));
request.setEnable(true);
// @@校验请求成功
this.requestPostWithOkAndReturn(STATUS_FLOW_UPDATE, request);
assertUpdateStatusFlow(DEFAULT_PROJECT_ID, statusFlow);
OrganizationStatusFlowSettingControllerTest.assertUpdateStatusFlow(request);
// 校验项目是否同步修改
OrganizationStatusFlowSettingControllerTest.assertRefUpdateStatusFlow(request);
// @@校验取消
request.setEnable(false);
this.requestPostWithOkAndReturn(STATUS_FLOW_UPDATE, request);
OrganizationStatusFlowSettingControllerTest.assertUpdateStatusFlow(request);
// 校验项目是否同步修改
OrganizationStatusFlowSettingControllerTest.assertRefUpdateStatusFlow(request);
// @校验是否开启组织模板
changeOrgTemplateEnable(true);
@ -250,11 +260,7 @@ public class ProjectStatusFlowSettingControllerTest extends BaseTest {
changeOrgTemplateEnable(false);
// @@状态不存在
request.getStatusFlows().get(0).setToId("1111");
assertErrorCode(this.requestPost(STATUS_FLOW_UPDATE, request), STATUS_ITEM_NOT_EXIST);
// @@校验组织是否存在
request.setScopeId("1111");
request.setToId("1111");
assertErrorCode(this.requestPost(STATUS_FLOW_UPDATE, request), NOT_FOUND);
// @@校验日志
@ -265,15 +271,6 @@ public class ProjectStatusFlowSettingControllerTest extends BaseTest {
requestPostPermissionTest(PermissionConstants.PROJECT_TEMPLATE_UPDATE, STATUS_FLOW_UPDATE, request);
}
private void assertUpdateStatusFlow(String scopeId, StatusFlowUpdateRequest.StatusFlowRequest statusFlow) {
List<String> statusIds = baseStatusItemService.getByScopeIdAndScene(scopeId, TemplateScene.BUG.name()).stream()
.map(StatusItem::getId).toList();
List<StatusFlow> statusFlows = baseStatusFlowService.getStatusFlows(statusIds);
Assertions.assertEquals(statusFlows.size(), 1);
Assertions.assertEquals(statusFlows.get(0).getFromId(), statusFlow.getFromId());
Assertions.assertEquals(statusFlows.get(0).getToId(), statusFlow.getToId());
}
@Test
@Order(5)
public void deleteStatusItem() throws Exception {

View File

@ -27,7 +27,8 @@ public enum CommonResultCode implements IResultCode {
DEFAULT_TEMPLATE_PERMISSION(100014, "default_template_permission_error"),
STATUS_ITEM_NOT_EXIST(100015, "status_item.not.exist"),
STATUS_ITEM_EXIST(100016, "status_item.exist"),
FIELD_VALIDATE_ERROR(100017, "field_validate_error");
FIELD_VALIDATE_ERROR(100017, "field_validate_error"),
STATUS_DEFINITION_REQUIRED_ERROR(100018, "status_definition_required_error");;
private int code;

View File

@ -1,46 +1,28 @@
package io.metersphere.system.dto.sdk.request;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.system.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class StatusDefinitionUpdateRequest implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "组织ID或项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank
@Size(min = 1, max = 50)
private String scopeId;
@Schema(description = "状态ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_definition.status_id.not_blank}")
@Size(min = 1, max = 50, message = "{status_definition.status_id.length_range}")
private String statusId;
@Schema(description = "使用场景", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_item.scene.not_blank}")
@EnumValue(enumClass = TemplateScene.class)
private String scene;
@Schema(description = "状态定义ID(在代码中定义)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_definition.definition_id.not_blank}")
@Size(min = 1, max = 100, message = "{status_definition.definition_id.length_range}")
private String definitionId;
@NotBlank
@Valid
private List<StatusDefinitionRequest> statusDefinitions;
@Data
public static class StatusDefinitionRequest implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "状态ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_definition.status_id.not_blank}")
@Size(min = 1, max = 50, message = "{status_definition.status_id.length_range}")
private String statusId;
@Schema(description = "状态定义ID(在代码中定义)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_definition.definition_id.not_blank}")
@Size(min = 1, max = 100, message = "{status_definition.definition_id.length_range}")
private String definitionId;
}
@Schema(description = "启用或者禁用", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull
private Boolean enable;
}

View File

@ -1,46 +1,28 @@
package io.metersphere.system.dto.sdk.request;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.system.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class StatusFlowUpdateRequest implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "组织ID或项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank
@Size(min = 1, max = 50)
private String scopeId;
@Schema(description = "起始状态ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_flow.from_id.not_blank}")
@Size(min = 1, max = 50, message = "{status_flow.from_id.length_range}")
private String fromId;
@Schema(description = "使用场景", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_item.scene.not_blank}")
@EnumValue(enumClass = TemplateScene.class)
private String scene;
@Schema(description = "目的状态ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_flow.to_id.not_blank}")
@Size(min = 1, max = 50, message = "{status_flow.to_id.length_range}")
private String toId;
@NotBlank
@Valid
private List<StatusFlowRequest> statusFlows;
@Data
public static class StatusFlowRequest implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "起始状态ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_flow.from_id.not_blank}")
@Size(min = 1, max = 50, message = "{status_flow.from_id.length_range}")
private String fromId;
@Schema(description = "目的状态ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_flow.to_id.not_blank}")
@Size(min = 1, max = 50, message = "{status_flow.to_id.length_range}")
private String toId;
}
@Schema(description = "启用或者禁用", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull
private Boolean enable;
}

View File

@ -38,6 +38,18 @@ public class BaseStatusDefinitionService {
statusDefinitionMapper.deleteByExample(example);
}
public void delete(String statusId, String definitionId) {
statusDefinitionMapper.deleteByPrimaryKey(statusId, definitionId);
}
public void add(StatusDefinition statusDefinition) {
StatusDefinitionExample example = new StatusDefinitionExample();
example.createCriteria()
.andStatusIdEqualTo(statusDefinition.getStatusId())
.andDefinitionIdEqualTo(statusDefinition.getDefinitionId());
statusDefinitionMapper.insert(statusDefinition);
}
public void deleteByStatusIds(List<String> statusItemIds) {
if (CollectionUtils.isEmpty(statusItemIds)) {
return;
@ -54,4 +66,12 @@ public class BaseStatusDefinitionService {
}
statusDefinitionMapper.batchInsert(statusDefinitions);
}
public void deleteByStatusIdsAndDefinitionId(List<String> statusIds, String definitionId) {
StatusDefinitionExample example = new StatusDefinitionExample();
example.createCriteria()
.andStatusIdIn(statusIds)
.andDefinitionIdEqualTo(definitionId);
statusDefinitionMapper.deleteByExample(example);
}
}

View File

@ -1,7 +1,5 @@
package io.metersphere.system.service;
import io.metersphere.system.dto.sdk.request.StatusFlowUpdateRequest;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.domain.StatusFlow;
import io.metersphere.system.domain.StatusFlowExample;
import io.metersphere.system.mapper.StatusFlowMapper;
@ -11,10 +9,7 @@ import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author jianxing
@ -40,34 +35,6 @@ public class BaseStatusFlowService {
return statusFlowMapper.selectByExample(example);
}
public void updateStatusFlow(List<String> deleteStatusItemIds, List<StatusFlowUpdateRequest.StatusFlowRequest> statusFlowRequests) {
// 先删除
StatusFlowExample example = new StatusFlowExample();
example.createCriteria().andFromIdIn(deleteStatusItemIds);
statusFlowMapper.deleteByExample(example);
example.clear();
example.createCriteria().andToIdIn(deleteStatusItemIds);
statusFlowMapper.deleteByExample(example);
// 再添加
List<StatusFlow> statusFlows = statusFlowRequests.stream().map(request -> {
StatusFlow statusFlow = new StatusFlow();
BeanUtils.copyBean(statusFlow, request);
statusFlow.setId(IDGenerator.nextStr());
return statusFlow;
}).toList();
statusFlowMapper.batchInsert(statusFlows);
}
public static List<String> getStatusIds(List<StatusFlowUpdateRequest.StatusFlowRequest> statusFlows) {
Set<String> statusIds = new HashSet<>();
statusFlows.forEach(statusFlow -> {
statusIds.add(statusFlow.getFromId());
statusIds.add(statusFlow.getToId());
});
return statusIds.stream().collect(Collectors.toList());
}
public void deleteByStatusId(String statusId) {
StatusFlowExample example = new StatusFlowExample();
example.createCriteria()
@ -100,4 +67,28 @@ public class BaseStatusFlowService {
});
statusFlowMapper.batchInsert(statusFlows);
}
public void add(StatusFlow statusFlow) {
statusFlow.setId(IDGenerator.nextStr());
statusFlowMapper.insert(statusFlow);
}
public void delete(String fromId, String toId) {
StatusFlowExample example = new StatusFlowExample();
example.createCriteria()
.andFromIdEqualTo(fromId)
.andToIdEqualTo(toId);
statusFlowMapper.deleteByExample(example);
}
public void deleteByFromIdsAndToIds(List<String> subProjectFromIds, List<String> subProjectToIds) {
if (CollectionUtils.isEmpty(subProjectFromIds) || CollectionUtils.isEmpty(subProjectToIds)) {
return;
}
StatusFlowExample example = new StatusFlowExample();
example.createCriteria()
.andFromIdIn(subProjectFromIds)
.andToIdIn(subProjectToIds);
statusFlowMapper.deleteByExample(example);
}
}

View File

@ -1,22 +1,23 @@
package io.metersphere.system.service;
import io.metersphere.sdk.constants.DefaultBugStatusItem;
import io.metersphere.sdk.constants.BugStatusDefinitionType;
import io.metersphere.sdk.constants.DefaultBugStatusItem;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.sdk.constants.TemplateScopeType;
import io.metersphere.system.dto.sdk.request.StatusDefinitionUpdateRequest;
import io.metersphere.system.dto.sdk.request.StatusFlowUpdateRequest;
import io.metersphere.system.dto.sdk.request.StatusItemAddRequest;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.controller.handler.result.CommonResultCode;
import io.metersphere.system.domain.StatusDefinition;
import io.metersphere.system.domain.StatusDefinitionExample;
import io.metersphere.system.domain.StatusFlow;
import io.metersphere.system.domain.StatusItem;
import io.metersphere.system.dto.StatusItemDTO;
import io.metersphere.system.dto.sdk.request.StatusDefinitionUpdateRequest;
import io.metersphere.system.dto.sdk.request.StatusFlowUpdateRequest;
import io.metersphere.system.dto.sdk.request.StatusItemAddRequest;
import io.metersphere.system.mapper.StatusDefinitionMapper;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@ -95,46 +96,42 @@ public class BaseStatusFlowSettingService {
*
* @param request
*/
public void updateStatusDefinition(StatusDefinitionUpdateRequest request) {
List<StatusDefinitionUpdateRequest.StatusDefinitionRequest> statusDefinitionsRequests = request.getStatusDefinitions();
List<StatusDefinition> statusDefinitions = statusDefinitionsRequests.stream()
.map(statusFlowRequest -> BeanUtils.copyBean(new StatusDefinition(), statusFlowRequest))
.toList();
List<String> statusIds = getStatusIds(statusDefinitionsRequests);
// 校验状态项是否存在
baseStatusItemService.checkStatusScope(request.getScopeId(), statusIds);
// 查询项目下所有的状态项
List<String> scopeStatusItemIds = baseStatusItemService.getByScopeIdAndScene(request.getScopeId(), request.getScene())
.stream()
.map(StatusItem::getId)
.toList();
updateStatusDefinition(scopeStatusItemIds, statusDefinitions);
protected void updateStatusDefinition(StatusItem statusItem, StatusDefinitionUpdateRequest request) {
handleSingleChoice(statusItem, request);
if (request.getEnable()) {
baseStatusDefinitionService.add(BeanUtils.copyBean(new StatusDefinition(), request));
} else {
baseStatusDefinitionService.delete(request.getStatusId(), request.getDefinitionId());
}
}
/**
* 设置状态定义
* 比如设置成项目
*
* @param scopeStatusItemIds
* @param statusDefinitions
* 处理单选的状态定义
* @param statusItem
* @param request
*/
public void updateStatusDefinition(List<String> scopeStatusItemIds, List<StatusDefinition> statusDefinitions) {
if (CollectionUtils.isEmpty(statusDefinitions)) {
return;
private void handleSingleChoice(StatusItem statusItem, StatusDefinitionUpdateRequest request) {
if (StringUtils.equals(statusItem.getScene(), TemplateScene.BUG.name())) {
BugStatusDefinitionType statusDefinitionType = BugStatusDefinitionType.getStatusDefinitionType(request.getDefinitionId());
if (!statusDefinitionType.getIsSingleChoice()) {
return;
}
// 如果是单选需要将其他状态取消勾选
if (request.getEnable()) {
List<String> statusIds = baseStatusItemService.getByScopeIdAndScene(statusItem.getScopeId(), statusItem.getScene())
.stream()
.map(StatusItem::getId)
.toList();
StatusDefinitionExample example = new StatusDefinitionExample();
example.createCriteria()
.andStatusIdIn(statusIds)
.andDefinitionIdEqualTo(request.getDefinitionId());
statusDefinitionMapper.deleteByExample(example);
} else {
// 单选默认必选不能取消
throw new MSException(CommonResultCode.STATUS_DEFINITION_REQUIRED_ERROR);
}
}
// 先删除组织或项目下的所有定义
StatusDefinitionExample example = new StatusDefinitionExample();
example.createCriteria().andStatusIdIn(scopeStatusItemIds);
statusDefinitionMapper.deleteByExample(example);
// 再添加
statusDefinitionMapper.batchInsert(statusDefinitions);
}
private List<String> getStatusIds(List<StatusDefinitionUpdateRequest.StatusDefinitionRequest> statusDefinitions) {
List<String> statusIds = statusDefinitions.stream()
.map(StatusDefinitionUpdateRequest.StatusDefinitionRequest::getStatusId)
.toList();
return statusIds;
}
/**
@ -143,13 +140,11 @@ public class BaseStatusFlowSettingService {
* @param request
*/
protected void updateStatusFlow(StatusFlowUpdateRequest request) {
List<StatusFlowUpdateRequest.StatusFlowRequest> statusFlows = request.getStatusFlows();
List<String> statusIds = baseStatusFlowService.getStatusIds(statusFlows);
baseStatusItemService.checkStatusScope(request.getScopeId(), statusIds);
List<String> statusItemIds = baseStatusItemService.getByScopeIdAndScene(request.getScopeId(), request.getScene())
.stream()
.map(StatusItem::getId).toList();
baseStatusFlowService.updateStatusFlow(statusItemIds, request.getStatusFlows());
if (request.getEnable()) {
baseStatusFlowService.add(BeanUtils.copyBean(new StatusFlow(), request));
} else {
baseStatusFlowService.delete(request.getFromId(), request.getToId());
}
}
protected void deleteStatusItem(String id) {
@ -232,20 +227,17 @@ public class BaseStatusFlowSettingService {
protected void handleAllTransferTo(StatusItemAddRequest request, String addStatusItemId) {
if (BooleanUtils.isTrue(request.getAllTransferTo())) {
List<StatusItem> statusItems = baseStatusItemService.getByScopeIdAndScene(request.getScopeId(), request.getScene());
List<StatusFlowUpdateRequest.StatusFlowRequest> statusFlows = statusItems.stream()
List<StatusFlowUpdateRequest> statusFlowUpdateRequests = statusItems.stream()
// 过滤自己
.filter(item -> !StringUtils.equals(item.getId(), addStatusItemId))
.map(item -> {
StatusFlowUpdateRequest.StatusFlowRequest statusFlow = new StatusFlowUpdateRequest.StatusFlowRequest();
statusFlow.setFromId(item.getId());
statusFlow.setToId(addStatusItemId);
return statusFlow;
StatusFlowUpdateRequest statusFlowRequest = new StatusFlowUpdateRequest();
statusFlowRequest.setFromId(item.getId());
statusFlowRequest.setToId(addStatusItemId);
statusFlowRequest.setEnable(true);
return statusFlowRequest;
}).toList();
StatusFlowUpdateRequest statusFlowUpdateRequest = new StatusFlowUpdateRequest();
statusFlowUpdateRequest.setScopeId(request.getScopeId());
statusFlowUpdateRequest.setScene(request.getScene());
statusFlowUpdateRequest.setStatusFlows(statusFlows);
updateStatusFlow(statusFlowUpdateRequest);
statusFlowUpdateRequests.forEach(this::updateStatusFlow);
}
}

View File

@ -85,10 +85,8 @@ public class BaseStatusItemService {
public StatusItem add(StatusItem statusItem) {
checkAddExist(statusItem);
statusItem.setInternal(false);
if (statusItem.getPos() == null) {
// 如果没有指定排序就放到最后
statusItem.setPos(getByScopeIdAndScene(statusItem.getScopeId(), statusItem.getScene()).size() + 1);
}
// 放到最后
statusItem.setPos(getByScopeIdAndScene(statusItem.getScopeId(), statusItem.getScene()).size() + 1);
return baseAdd(statusItem);
}
@ -152,6 +150,9 @@ public class BaseStatusItemService {
}
public List<StatusItem> getByScopeIdsAndScene(List<String> scopeIds, String scene) {
if (CollectionUtils.isEmpty(scopeIds)) {
return List.of();
}
StatusItemExample example = new StatusItemExample();
example.createCriteria().andScopeIdIn(scopeIds).andSceneEqualTo(scene);
return statusItemMapper.selectByExample(example);

View File

@ -34,7 +34,8 @@ public class OrganizationStatusFlowSettingLogService {
public LogDTO updateStatusDefinitionLog(StatusDefinitionUpdateRequest request) {
return updateStatusFlowSettingLog(request.getScopeId(), request.getScene());
StatusItem statusItem = statusItemMapper.selectByPrimaryKey(request.getStatusId());
return updateStatusFlowSettingLog(statusItem.getScopeId(), statusItem.getScene());
}
public LogDTO addStatusItemLog(StatusItemAddRequest request) {
@ -52,7 +53,8 @@ public class OrganizationStatusFlowSettingLogService {
}
public LogDTO updateStatusFlowLog(StatusFlowUpdateRequest request) {
return updateStatusFlowSettingLog(request.getScopeId(), request.getScene());
StatusItem statusItem = statusItemMapper.selectByPrimaryKey(request.getFromId());
return updateStatusFlowSettingLog(statusItem.getScopeId(), statusItem.getScene());
}
public LogDTO updateStatusFlowSettingLog(String scopeId, String scene) {

View File

@ -1,17 +1,21 @@
package io.metersphere.system.service;
import io.metersphere.sdk.constants.BugStatusDefinitionType;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.sdk.constants.TemplateScopeType;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.system.domain.StatusDefinition;
import io.metersphere.system.domain.StatusDefinitionExample;
import io.metersphere.system.domain.StatusFlow;
import io.metersphere.system.domain.StatusItem;
import io.metersphere.system.dto.StatusItemDTO;
import io.metersphere.system.dto.sdk.request.StatusDefinitionUpdateRequest;
import io.metersphere.system.dto.sdk.request.StatusFlowUpdateRequest;
import io.metersphere.system.dto.sdk.request.StatusItemAddRequest;
import io.metersphere.system.dto.sdk.request.StatusItemUpdateRequest;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.system.domain.StatusDefinition;
import io.metersphere.system.domain.StatusFlow;
import io.metersphere.system.domain.StatusItem;
import io.metersphere.system.dto.StatusItemDTO;
import io.metersphere.system.mapper.BaseProjectMapper;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@ -20,6 +24,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
@ -54,12 +59,13 @@ public class OrganizationStatusFlowSettingService extends BaseStatusFlowSettingS
*
* @param request
*/
@Override
public void updateStatusDefinition(StatusDefinitionUpdateRequest request) {
OrganizationService.checkResourceExist(request.getScopeId());
organizationTemplateService.checkOrganizationTemplateEnable(request.getScopeId(), request.getScene());
super.updateStatusDefinition(request);
updateRefProjectStatusDefinition(request);
StatusItem statusItem = baseStatusItemService.getWithCheck(request.getStatusId());
OrganizationService.checkResourceExist(statusItem.getScopeId());
organizationTemplateService.checkOrganizationTemplateEnable(statusItem.getScopeId(), statusItem.getScene());
super.updateStatusDefinition(statusItem, request);
// 同步更新项目级别状态定义
updateRefProjectStatusDefinition(statusItem, request);
}
/**
@ -68,49 +74,55 @@ public class OrganizationStatusFlowSettingService extends BaseStatusFlowSettingS
* @param request
* @return
*/
public void updateRefProjectStatusDefinition(StatusDefinitionUpdateRequest request) {
String orgId = request.getScopeId();
List<StatusDefinitionUpdateRequest.StatusDefinitionRequest> orgStatusDefinitions = request.getStatusDefinitions();
if (orgStatusDefinitions == null) {
return;
}
List<String> projectIds = baseProjectMapper.getProjectIdByOrgId(orgId);
SubListUtils.dealForSubList(projectIds, 200, (subProjectIds) -> {
public void updateRefProjectStatusDefinition(StatusItem orgStatusItem, StatusDefinitionUpdateRequest request) {
handleRefSingleChoice(orgStatusItem, request);
List<StatusItem> statusItems = baseStatusItemService.getByRefId(request.getStatusId());
SubListUtils.dealForSubList(statusItems, 200, (subStatusItems) -> {
// 每次处理200条
List<StatusDefinition> statusDefinitions = new ArrayList<>();
// 查询组织下所有项目的状态项
List<StatusItem> statusItems = baseStatusItemService.getByScopeIdsAndScene(subProjectIds, request.getScene());
Map<String, List<StatusItem>> projectStatusItemMap = statusItems
.stream()
.collect(Collectors.groupingBy(StatusItem::getScopeId));
for (String projectId : projectStatusItemMap.keySet()) {
List<StatusItem> projectStatusItems = projectStatusItemMap.get(projectId);
// 构建map键为组织状态ID值为项目字状态ID
Map<String, String> refFieldMap = projectStatusItems
.stream()
.collect(Collectors.toMap(StatusItem::getRefId, StatusItem::getId));
// 根据组织状态ID替换为项目状态ID
List<StatusDefinition> projectStatusDefinitions = orgStatusDefinitions.stream()
.map(item -> {
StatusDefinition statusDefinition = BeanUtils.copyBean(new StatusDefinition(), item);
statusDefinition.setStatusId(refFieldMap.get(item.getStatusId()));
return statusDefinition;
})
.filter(item -> StringUtils.isNotBlank(item.getStatusId()))
if (request.getEnable()) {
List<StatusDefinition> projectStatusDefinitions = subStatusItems.stream().map(statusItem -> {
StatusDefinition statusDefinition = new StatusDefinition();
statusDefinition.setStatusId(((StatusItem) statusItem).getId());
statusDefinition.setDefinitionId(request.getDefinitionId());
return statusDefinition;
}).toList();
baseStatusDefinitionService.batchAdd(projectStatusDefinitions);
} else {
List<String> projectStatusIds = subStatusItems.stream()
.map(statusItem -> ((StatusItem) statusItem).getId())
.toList();
statusDefinitions.addAll(projectStatusDefinitions);
baseStatusDefinitionService.deleteByStatusIdsAndDefinitionId(projectStatusIds, request.getDefinitionId());
}
// 删除项目下的状态项
List<String> scopeStatusItemIds = statusItems
.stream()
.map(StatusItem::getId)
.toList();
updateStatusDefinition(scopeStatusItemIds, statusDefinitions);
});
}
/**
* 处理单选的状态定义
*
* @param request
*/
private void handleRefSingleChoice(StatusItem orgStatusItem, StatusDefinitionUpdateRequest request) {
if (StringUtils.equals(orgStatusItem.getScene(), TemplateScene.BUG.name())) {
BugStatusDefinitionType statusDefinitionType = BugStatusDefinitionType.getStatusDefinitionType(request.getDefinitionId());
if (!statusDefinitionType.getIsSingleChoice()) {
return;
}
List<String> projectIds = baseProjectMapper.getProjectIdByOrgId(orgStatusItem.getScopeId());
SubListUtils.dealForSubList(projectIds, 200, (subProjectIds) -> {
// 查询组织下所有项目的状态项
List<StatusItem> statusItems = baseStatusItemService.getByScopeIdsAndScene(subProjectIds, orgStatusItem.getScene());
List<String> statusItemIds = statusItems.stream().map(StatusItem::getId).toList();
StatusDefinitionExample example = new StatusDefinitionExample();
example.createCriteria()
.andStatusIdIn(statusItemIds)
.andDefinitionIdEqualTo(request.getDefinitionId());
// 如果是单选需要将其他状态取消勾选
statusDefinitionMapper.deleteByExample(example);
});
}
}
/**
* 添加状态选项
*
@ -207,14 +219,14 @@ public class OrganizationStatusFlowSettingService extends BaseStatusFlowSettingS
*/
public void deleteRefStatusItem(String orgStatusItemId) {
// 删除关联的项目状态项
baseStatusItemService.deleteByRefId(orgStatusItemId);
List<String> statusItemIds = baseStatusItemService.getStatusItemIdByRefId(orgStatusItemId);
SubListUtils.dealForSubList(statusItemIds, 100, (subProjectIds) -> {
SubListUtils.dealForSubList(statusItemIds, 100, (subStatusItemIds) -> {
// 删除相关的状态定义
baseStatusDefinitionService.deleteByStatusIds(statusItemIds);
baseStatusDefinitionService.deleteByStatusIds(subStatusItemIds);
// 删除相关的状态流
baseStatusFlowService.deleteByStatusIds(statusItemIds);
baseStatusFlowService.deleteByStatusIds(subStatusItemIds);
});
baseStatusItemService.deleteByRefId(orgStatusItemId);
}
/**
@ -223,10 +235,13 @@ public class OrganizationStatusFlowSettingService extends BaseStatusFlowSettingS
* @param request
*/
public void updateStatusFlow(StatusFlowUpdateRequest request) {
OrganizationService.checkResourceExist(request.getScopeId());
organizationTemplateService.checkOrganizationTemplateEnable(request.getScopeId(), request.getScene());
// 同步添加项目级别状态流
StatusItem fromStatusItem = baseStatusItemService.getWithCheck(request.getFromId());
StatusItem toStatusItem = baseStatusItemService.getWithCheck(request.getToId());
OrganizationService.checkResourceExist(fromStatusItem.getScopeId());
OrganizationService.checkResourceExist(toStatusItem.getScopeId());
organizationTemplateService.checkOrganizationTemplateEnable(fromStatusItem.getScopeId(), fromStatusItem.getScene());
super.updateStatusFlow(request);
// 同步添加项目级别状态流
updateRefProjectStatusFlow(request);
}
@ -237,45 +252,50 @@ public class OrganizationStatusFlowSettingService extends BaseStatusFlowSettingS
* @return
*/
public void updateRefProjectStatusFlow(StatusFlowUpdateRequest request) {
String orgId = request.getScopeId();
List<StatusFlowUpdateRequest.StatusFlowRequest> statusFlowRequests = request.getStatusFlows();
if (statusFlowRequests == null) {
return;
}
List<String> projectIds = baseProjectMapper.getProjectIdByOrgId(orgId);
SubListUtils.dealForSubList(projectIds, 100, (subProjectIds) -> {
// 获取from和to状态项
List<StatusItem> fromStatusItems = baseStatusItemService.getByRefId(request.getFromId());
Map<String, StatusItem> fromStatusItemMap = fromStatusItems.stream()
.collect(Collectors.toMap(StatusItem::getScopeId, Function.identity()));
List<StatusItem> toStatusItems = baseStatusItemService.getByRefId(request.getToId());
Map<String, StatusItem> toStatusItemMap = toStatusItems.stream()
.collect(Collectors.toMap(StatusItem::getScopeId, Function.identity()));
if (request.getEnable()) {
// 同步添加项目级别状态流
List<StatusFlow> statusFlows = new ArrayList<>();
// 查询组织下所有项目的状态项
List<StatusItem> statusItems = baseStatusItemService.getByScopeIdsAndScene(subProjectIds, request.getScene());
Map<String, List<StatusItem>> projectStatusItemMap = statusItems
.stream()
.collect(Collectors.groupingBy(StatusItem::getScopeId));
List<String> statusItemIds = statusItems.stream().map(StatusItem::getId).toList();
for (String projectId : projectStatusItemMap.keySet()) {
// 构建map键为组织状态ID值为项目字状态ID
Map<String, String> refStatusItemMap = projectStatusItemMap.get(projectId)
.stream()
.collect(Collectors.toMap(StatusItem::getRefId, StatusItem::getId));
// 根据组织状态ID替换为项目状态ID
List<StatusFlow> projectStatusFlows = statusFlowRequests.stream()
.map(item -> {
StatusFlow statusFlow = new StatusFlow();
statusFlow.setToId(refStatusItemMap.get(item.getToId()));
statusFlow.setFromId(refStatusItemMap.get(item.getFromId()));
return statusFlow;
})
.filter(item -> item.getToId() != null && item.getFromId() != null)
.toList();
statusFlows.addAll(projectStatusFlows);
for (String projectId : fromStatusItemMap.keySet()) {
String fromId = fromStatusItemMap.get(projectId).getId();
String toId = toStatusItemMap.get(projectId).getId();
if (StringUtils.isNotBlank(fromId) && StringUtils.isNotBlank(toId)) {
StatusFlow statusFlow = new StatusFlow();
statusFlow.setFromId(fromId);
statusFlow.setToId(toId);
statusFlow.setId(IDGenerator.nextStr());
statusFlows.add(statusFlow);
}
}
// 先删除
baseStatusFlowService.deleteByStatusIds(statusItemIds);
// 在添加
baseStatusFlowService.batchAdd(statusFlows);
});
SubListUtils.dealForSubList(statusFlows, 200, baseStatusFlowService::batchAdd);
} else {
// 同步删除项目级别状态流
List<String> subProjectFromIds = new ArrayList<>();
List<String> subProjectToIds = new ArrayList<>();
for (String projectId : fromStatusItemMap.keySet()) {
String fromId = fromStatusItemMap.get(projectId).getId();
String toId = toStatusItemMap.get(projectId).getId();
if (StringUtils.isNotBlank(fromId) && StringUtils.isNotBlank(toId)) {
subProjectFromIds.add(fromId);
subProjectToIds.add(toId);
if (subProjectFromIds.size() > 100) {
// 分批删除
baseStatusFlowService.deleteByFromIdsAndToIds(subProjectFromIds, subProjectToIds);
subProjectFromIds.clear();
subProjectToIds.clear();
}
}
}
baseStatusFlowService.deleteByFromIdsAndToIds(subProjectFromIds, subProjectToIds);
}
}
@Override

View File

@ -17,6 +17,8 @@ import io.metersphere.system.domain.*;
import io.metersphere.system.dto.StatusItemDTO;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.mapper.OrganizationParameterMapper;
import io.metersphere.system.mapper.StatusDefinitionMapper;
import io.metersphere.system.mapper.StatusFlowMapper;
import io.metersphere.system.mapper.StatusItemMapper;
import io.metersphere.system.service.BaseStatusDefinitionService;
import io.metersphere.system.service.BaseStatusFlowService;
@ -33,10 +35,10 @@ import org.springframework.test.web.servlet.MvcResult;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static io.metersphere.system.controller.handler.result.CommonResultCode.STATUS_ITEM_EXIST;
import static io.metersphere.system.controller.handler.result.CommonResultCode.STATUS_ITEM_NOT_EXIST;
import static io.metersphere.system.controller.handler.result.CommonResultCode.*;
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
import static io.metersphere.system.controller.result.SystemResultCode.ORGANIZATION_TEMPLATE_PERMISSION;
@ -44,7 +46,7 @@ import static io.metersphere.system.controller.result.SystemResultCode.ORGANIZAT
* @author jianxing
* @date : 2023-10-9
*/
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class OrganizationStatusFlowSettingControllerTest extends BaseTest {
@ -59,6 +61,7 @@ public class OrganizationStatusFlowSettingControllerTest extends BaseTest {
private static final String STATUS_FLOW_UPDATE = "status/flow/update";
private static StatusItem addStatusItem;
private static StatusItem anotherAddStatusItem;
@Resource
private StatusItemMapper statusItemMapper;
@ -88,7 +91,7 @@ public class OrganizationStatusFlowSettingControllerTest extends BaseTest {
requestGetPermissionTest(PermissionConstants.ORGANIZATION_TEMPLATE_READ, GET, DEFAULT_ORGANIZATION_ID, TemplateScene.BUG.name());
}
public static void assertDefaultStatusFlowSettingInit( List<StatusItemDTO> statusItemDTOS) {
public static void assertDefaultStatusFlowSettingInit(List<StatusItemDTO> statusItemDTOS) {
Map<String, String> nameIdMap = statusItemDTOS.stream()
.collect(Collectors.toMap(StatusItem::getId, StatusItem::getName));
// 校验默认的状态定义是否初始化正确
@ -155,7 +158,8 @@ public class OrganizationStatusFlowSettingControllerTest extends BaseTest {
request.setName("test2");
request.setAllTransferTo(true);
mvcResult = this.requestPostWithOkAndReturn(STATUS_ADD, request);
statusItemId = getResultData(mvcResult, StatusItem.class).getId();
anotherAddStatusItem = getResultData(mvcResult, StatusItem.class);
statusItemId = anotherAddStatusItem.getId();
assertAllTransferTo(statusItemId, request.getScopeId());
assertRefAllTransferTo(statusItemId);
@ -185,6 +189,7 @@ public class OrganizationStatusFlowSettingControllerTest extends BaseTest {
/**
* 校验 allTransferTo
*
* @param statusItemId
*/
public static void assertAllTransferTo(String statusItemId, String scopeId) {
@ -239,6 +244,11 @@ public class OrganizationStatusFlowSettingControllerTest extends BaseTest {
Assertions.assertEquals(statusItem.getRemark(), request.getRemark());
assertRefStatusItem(statusItem);
// 提升覆盖率
request.setName(null);
this.requestPostWithOkAndReturn(STATUS_UPDATE, request);
baseStatusItemService.getByScopeIdsAndScene(null, TemplateScene.BUG.name());
// @校验是否开启组织模板
changeOrgTemplateEnable(false);
assertErrorCode(this.requestPost(STATUS_UPDATE, request), ORGANIZATION_TEMPLATE_PERMISSION);
@ -260,23 +270,45 @@ public class OrganizationStatusFlowSettingControllerTest extends BaseTest {
requestPostPermissionTest(PermissionConstants.ORGANIZATION_TEMPLATE_UPDATE, STATUS_UPDATE, request);
}
@Test
@Order(3)
public void updateStatusDefinition() throws Exception {
StatusDefinitionUpdateRequest request = new StatusDefinitionUpdateRequest();
request.setScene(TemplateScene.BUG.name());
request.setScopeId(DEFAULT_ORGANIZATION_ID);
StatusDefinitionUpdateRequest.StatusDefinitionRequest statusDefinition = new StatusDefinitionUpdateRequest.StatusDefinitionRequest();
statusDefinition.setStatusId(addStatusItem.getId());
statusDefinition.setDefinitionId(BugStatusDefinitionType.END.name());
request.setStatusDefinitions(List.of(statusDefinition));
request.setStatusId(addStatusItem.getId());
request.setDefinitionId(BugStatusDefinitionType.END.name());
request.setEnable(true);
// @@校验请求成功
this.requestPostWithOkAndReturn(STATUS_DEFINITION_UPDATE, request);
assertUpdateStatusDefinition(DEFAULT_ORGANIZATION_ID);
assertUpdateStatusDefinition(request);
// 校验项目是否同步修改
assertUpdateStatusDefinition(DEFAULT_PROJECT_ID);
assertRefUpdateStatusDefinition(request);
// 取消关联
request.setEnable(false);
this.requestPostWithOkAndReturn(STATUS_DEFINITION_UPDATE, request);
assertUpdateStatusDefinition(request);
// 校验项目是否同步修改
assertRefUpdateStatusDefinition(request);
// @测试单选
request.setStatusId(addStatusItem.getId());
request.setDefinitionId(BugStatusDefinitionType.START.name());
request.setEnable(true);
this.requestPostWithOkAndReturn(STATUS_DEFINITION_UPDATE, request);
assertUpdateStatusDefinition(request);
// 校验项目是否同步修改
assertRefUpdateStatusDefinition(request);
// 校验单选
assertSingleChoiceUpdateStatusDefinition(request);
// 校验单选禁止取消
request.setEnable(false);
assertErrorCode(this.requestPost(STATUS_DEFINITION_UPDATE, request), STATUS_DEFINITION_REQUIRED_ERROR);
// 设置回来避免其他地方校验出错
StatusItem newStatusItem = getNewStatusItem(addStatusItem.getScopeId());
request.setStatusId(newStatusItem.getId());
request.setEnable(true);
this.requestPostWithOkAndReturn(STATUS_DEFINITION_UPDATE, request);
// @校验是否开启组织模板
changeOrgTemplateEnable(false);
@ -284,11 +316,7 @@ public class OrganizationStatusFlowSettingControllerTest extends BaseTest {
changeOrgTemplateEnable(true);
// @@状态不存在
request.getStatusDefinitions().get(0).setStatusId("1111");
assertErrorCode(this.requestPost(STATUS_DEFINITION_UPDATE, request), STATUS_ITEM_NOT_EXIST);
// @@校验组织是否存在
request.setScopeId("1111");
request.setStatusId("1111");
assertErrorCode(this.requestPost(STATUS_DEFINITION_UPDATE, request), NOT_FOUND);
// @@校验日志
@ -299,39 +327,82 @@ public class OrganizationStatusFlowSettingControllerTest extends BaseTest {
requestPostPermissionTest(PermissionConstants.ORGANIZATION_TEMPLATE_UPDATE, STATUS_DEFINITION_UPDATE, request);
}
private void assertUpdateStatusDefinition(String scopeId) {
List<String> statusIds = baseStatusItemService.getByScopeIdAndScene(scopeId, TemplateScene.BUG.name()).stream().map(StatusItem::getId).toList();
List<StatusDefinition> statusDefinitions = baseStatusDefinitionService.getStatusDefinitions(statusIds);
Assertions.assertEquals(statusDefinitions.size(), 1);
Assertions.assertEquals(statusDefinitions.get(0).getDefinitionId(), BugStatusDefinitionType.END.name());
public static StatusItem getNewStatusItem(String scopeId) {
StatusItemExample example = new StatusItemExample();
example.createCriteria()
.andNameEqualTo(DefaultBugStatusItemName.NEW)
.andScopeIdEqualTo(scopeId);
StatusItemMapper statusItemMapper = CommonBeanFactory.getBean(StatusItemMapper.class);
return statusItemMapper.selectByExample(example).get(0);
}
public static void assertUpdateStatusDefinition(StatusDefinitionUpdateRequest request) {
StatusDefinitionExample example = new StatusDefinitionExample();
example.createCriteria()
.andStatusIdEqualTo(request.getStatusId())
.andDefinitionIdEqualTo(request.getDefinitionId());
StatusDefinitionMapper statusDefinitionMapper = CommonBeanFactory.getBean(StatusDefinitionMapper.class);
List<StatusDefinition> statusDefinitions = statusDefinitionMapper.selectByExample(example);
if (request.getEnable()) {
Assertions.assertTrue(statusDefinitions.size() == 1);
} else {
Assertions.assertTrue(statusDefinitions.size() == 0);
}
}
public static void assertSingleChoiceUpdateStatusDefinition(StatusDefinitionUpdateRequest request) {
// 查询当前组织或项目下的状态项
BaseStatusItemService baseStatusItemService = CommonBeanFactory.getBean(BaseStatusItemService.class);
StatusItem statusItem = baseStatusItemService.getWithCheck(request.getStatusId());
List<String> scopeStatusItemIds = baseStatusItemService.getByScopeIdAndScene(statusItem.getScopeId(), TemplateScene.BUG.name())
.stream().map(StatusItem::getId).toList();
// 查询当前组织或项目下的该状态定义
StatusDefinitionExample example = new StatusDefinitionExample();
example.createCriteria()
.andStatusIdIn(scopeStatusItemIds)
.andDefinitionIdEqualTo(request.getDefinitionId());
StatusDefinitionMapper statusDefinitionMapper = CommonBeanFactory.getBean(StatusDefinitionMapper.class);
List<StatusDefinition> statusDefinitions = statusDefinitionMapper.selectByExample(example);
if (request.getEnable()) {
Assertions.assertTrue(statusDefinitions.size() == 1);
}
}
public static void assertRefUpdateStatusDefinition(StatusDefinitionUpdateRequest request) {
BaseStatusItemService baseStatusItemService = CommonBeanFactory.getBean(BaseStatusItemService.class);
List<StatusItem> projectStatusItem = baseStatusItemService.getByRefId(request.getStatusId());
StatusDefinitionUpdateRequest projectRequest = BeanUtils.copyBean(new StatusDefinitionUpdateRequest(), request);
projectStatusItem.forEach(statusItem -> {
projectRequest.setStatusId(statusItem.getId());
assertUpdateStatusDefinition(projectRequest);
});
}
@Test
@Order(4)
public void updateStatusFlow() throws Exception {
StatusFlowUpdateRequest request = new StatusFlowUpdateRequest();
request.setScopeId(DEFAULT_ORGANIZATION_ID);
request.setScene(TemplateScene.BUG.name());
StatusFlowUpdateRequest.StatusFlowRequest statusFlow = new StatusFlowUpdateRequest.StatusFlowRequest();
statusFlow.setFromId(addStatusItem.getId());
StatusItemExample example = new StatusItemExample();
example.createCriteria().andScopeIdEqualTo(DEFAULT_ORGANIZATION_ID).andSceneEqualTo(TemplateScene.BUG.name());
StatusItem targetStatusItem = statusItemMapper.selectByExample(example).stream()
.filter(item -> !StringUtils.equals(addStatusItem.getId(), item.getId()))
.findFirst()
.get();
statusFlow.setToId(targetStatusItem.getId());
request.setStatusFlows(List.of(statusFlow));
request.setFromId(anotherAddStatusItem.getId());
request.setToId(addStatusItem.getId());
request.setEnable(true);
// @@校验请求成功
this.requestPostWithOkAndReturn(STATUS_FLOW_UPDATE, request);
assertUpdateStatusFlow(DEFAULT_ORGANIZATION_ID, statusFlow);
assertUpdateStatusFlow(request);
// 校验项目是否同步修改
StatusFlowUpdateRequest.StatusFlowRequest projectStatusFlow = new StatusFlowUpdateRequest.StatusFlowRequest();
projectStatusFlow.setFromId(baseStatusItemService.getByRefId(statusFlow.getFromId()).get(0).getId());
projectStatusFlow.setToId(baseStatusItemService.getByRefId(statusFlow.getToId()).get(0).getId());
assertUpdateStatusFlow(DEFAULT_PROJECT_ID, projectStatusFlow);
assertRefUpdateStatusFlow(request);
// @@校验取消
request.setEnable(false);
this.requestPostWithOkAndReturn(STATUS_FLOW_UPDATE, request);
assertUpdateStatusFlow(request);
// 校验项目是否同步修改
assertRefUpdateStatusFlow(request);
// 增加覆盖率
baseStatusFlowService.deleteByFromIdsAndToIds(null, null);
// @校验是否开启组织模板
changeOrgTemplateEnable(false);
@ -339,11 +410,7 @@ public class OrganizationStatusFlowSettingControllerTest extends BaseTest {
changeOrgTemplateEnable(true);
// @@状态不存在
request.getStatusFlows().get(0).setToId("1111");
assertErrorCode(this.requestPost(STATUS_FLOW_UPDATE, request), STATUS_ITEM_NOT_EXIST);
// @@校验组织是否存在
request.setScopeId("1111");
request.setToId("1111");
assertErrorCode(this.requestPost(STATUS_FLOW_UPDATE, request), NOT_FOUND);
// @@校验日志
@ -354,13 +421,35 @@ public class OrganizationStatusFlowSettingControllerTest extends BaseTest {
requestPostPermissionTest(PermissionConstants.ORGANIZATION_TEMPLATE_UPDATE, STATUS_FLOW_UPDATE, request);
}
private void assertUpdateStatusFlow(String scopeId, StatusFlowUpdateRequest.StatusFlowRequest statusFlow) {
List<String> statusIds = baseStatusItemService.getByScopeIdAndScene(scopeId, TemplateScene.BUG.name()).stream()
.map(StatusItem::getId).toList();
List<StatusFlow> statusFlows = baseStatusFlowService.getStatusFlows(statusIds);
Assertions.assertEquals(statusFlows.size(), 1);
Assertions.assertEquals(statusFlows.get(0).getFromId(), statusFlow.getFromId());
Assertions.assertEquals(statusFlows.get(0).getToId(), statusFlow.getToId());
public static void assertUpdateStatusFlow(StatusFlowUpdateRequest request) {
StatusFlowExample example = new StatusFlowExample();
example.createCriteria()
.andFromIdEqualTo(request.getFromId())
.andToIdEqualTo(request.getToId());
StatusFlowMapper statusFlowMapper = CommonBeanFactory.getBean(StatusFlowMapper.class);
List<StatusFlow> statusFlows = statusFlowMapper.selectByExample(example);
if (request.getEnable()) {
Assertions.assertTrue(statusFlows.size() == 1);
} else {
Assertions.assertTrue(statusFlows.size() == 0);
}
}
public static void assertRefUpdateStatusFlow(StatusFlowUpdateRequest request) {
BaseStatusItemService baseStatusItemService = CommonBeanFactory.getBean(BaseStatusItemService.class);
List<StatusItem> fromStatusItems = baseStatusItemService.getByRefId(request.getFromId());
Map<String, StatusItem> fromStatusItemMap = fromStatusItems.stream()
.collect(Collectors.toMap(StatusItem::getScopeId, Function.identity()));
List<StatusItem> toStatusItems = baseStatusItemService.getByRefId(request.getToId());
Map<String, StatusItem> toStatusItemMap = toStatusItems.stream()
.collect(Collectors.toMap(StatusItem::getScopeId, Function.identity()));
StatusFlowUpdateRequest projectRequest = BeanUtils.copyBean(new StatusFlowUpdateRequest(), request);
for (String projectId : fromStatusItemMap.keySet()) {
projectRequest.setFromId(fromStatusItemMap.get(projectId).getId());
projectRequest.setToId(toStatusItemMap.get(projectId).getId());
assertUpdateStatusFlow(projectRequest);
}
}
@Test
@ -372,11 +461,14 @@ public class OrganizationStatusFlowSettingControllerTest extends BaseTest {
changeOrgTemplateEnable(true);
// @@请求成功
List<String> projectStatusItemIds = baseStatusItemService.getStatusItemIdByRefId(addStatusItem.getId());
this.requestGetWithOk(STATUS_DELETE, addStatusItem.getId());
Assertions.assertNull(statusItemMapper.selectByPrimaryKey(addStatusItem.getId()));
Assertions.assertTrue(CollectionUtils.isEmpty(baseStatusItemService.getStatusItemIdByRefId(addStatusItem.getId())));
Assertions.assertTrue(CollectionUtils.isEmpty(baseStatusDefinitionService.getStatusDefinitions(List.of(addStatusItem.getId()))));
Assertions.assertTrue(CollectionUtils.isEmpty(baseStatusFlowService.getStatusFlows(List.of(addStatusItem.getId()))));
Assertions.assertTrue(CollectionUtils.isEmpty(baseStatusDefinitionService.getStatusDefinitions(projectStatusItemIds)));
Assertions.assertTrue(CollectionUtils.isEmpty(baseStatusFlowService.getStatusFlows(projectStatusItemIds)));
// @@校验 NOT_FOUND 异常
assertErrorCode(this.requestGet(STATUS_DELETE, "1111"), NOT_FOUND);
@ -430,7 +522,7 @@ public class OrganizationStatusFlowSettingControllerTest extends BaseTest {
public static void assertSortStatusItem(String scopeId, List<String> statusIds) {
BaseStatusItemService baseStatusItemService = CommonBeanFactory.getBean(BaseStatusItemService.class);
List<StatusItem> statusItems = baseStatusItemService.getByScopeId(scopeId);
List<StatusItem> statusItems = baseStatusItemService.getByScopeIdAndScene(scopeId, TemplateScene.BUG.name());
for (int i = 0; i < statusIds.size(); i++) {
String statusId = statusIds.get(i);
// 根据statusId 查询

View File

@ -1,45 +1,27 @@
package io.metersphere.system.controller.param;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.system.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class StatusDefinitionUpdateRequestDefinition implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "状态ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_definition.status_id.not_blank}")
@Size(min = 1, max = 50, message = "{status_definition.status_id.length_range}")
private String statusId;
@Schema(description = "组织ID或项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank
@Size(min = 1, max = 50)
private String scopeId;
@Schema(description = "使用场景", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank
@EnumValue(enumClass = TemplateScene.class)
private String scene;
@Schema(description = "状态定义ID(在代码中定义)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_definition.definition_id.not_blank}")
@Size(min = 1, max = 100, message = "{status_definition.definition_id.length_range}")
private String definitionId;
@NotBlank
@Valid
private List<StatusDefinitionRequestStatusDefinition> statusDefinitions;
@Data
public static class StatusDefinitionRequestStatusDefinition implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "状态ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_definition.status_id.not_blank}")
@Size(min = 1, max = 50, message = "{status_definition.status_id.length_range}")
private String statusId;
@Schema(description = "状态定义ID(在代码中定义)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_definition.definition_id.not_blank}")
@Size(min = 1, max = 100, message = "{status_definition.definition_id.length_range}")
private String definitionId;
}
@Schema(description = "启用或者禁用", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull
private Boolean enable;
}

View File

@ -1,46 +1,28 @@
package io.metersphere.system.controller.param;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.system.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class StatusFlowUpdateRequestDefinition implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "组织ID或项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank
@Size(min = 1, max = 50)
private String scopeId;
@Schema(description = "起始状态ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_flow.from_id.not_blank}")
@Size(min = 1, max = 50, message = "{status_flow.from_id.length_range}")
private String fromId;
@Schema(description = "使用场景", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_item.scene.not_blank}")
@EnumValue(enumClass = TemplateScene.class)
private String scene;
@Schema(description = "目的状态ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_flow.to_id.not_blank}")
@Size(min = 1, max = 50, message = "{status_flow.to_id.length_range}")
private String toId;
@NotBlank
@Valid
private List<StatusFlowRequestDefinition> statusFlows;
@Data
public static class StatusFlowRequestDefinition implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "起始状态ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_flow.from_id.not_blank}")
@Size(min = 1, max = 50, message = "{status_flow.from_id.length_range}")
private String fromId;
@Schema(description = "目的状态ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{status_flow.to_id.not_blank}")
@Size(min = 1, max = 50, message = "{status_flow.to_id.length_range}")
private String toId;
}
@Schema(description = "启用或者禁用", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull
private Boolean enable;
}