diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/controller/CaseReviewController.java b/backend/services/case-management/src/main/java/io/metersphere/functional/controller/CaseReviewController.java index 743f7c2650..205e014bbc 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/controller/CaseReviewController.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/controller/CaseReviewController.java @@ -1,22 +1,28 @@ package io.metersphere.functional.controller; -import io.metersphere.functional.request.CaseReviewAddRequest; import io.metersphere.functional.request.CaseReviewFollowerRequest; +import io.metersphere.functional.request.CaseReviewRequest; import io.metersphere.functional.service.CaseReviewLogService; +import io.metersphere.functional.service.CaseReviewNoticeService; import io.metersphere.functional.service.CaseReviewService; import io.metersphere.sdk.constants.PermissionConstants; +import io.metersphere.system.domain.User; import io.metersphere.system.log.annotation.Log; import io.metersphere.system.log.constants.OperationLogType; +import io.metersphere.system.notice.annotation.SendNotice; +import io.metersphere.system.notice.constants.NoticeConstants; import io.metersphere.system.utils.SessionUtils; +import io.metersphere.validation.groups.Updated; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; +import org.apache.shiro.authz.annotation.Logical; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.List; @Tag(name = "用例管理-用例评审") @RestController @@ -29,11 +35,21 @@ public class CaseReviewController { @PostMapping("/add") @Operation(summary = "用例管理-用例评审-创建用例评审") @Log(type = OperationLogType.ADD, expression = "#msClass.addCaseReviewLog(#request)", msClass = CaseReviewLogService.class) + @SendNotice(taskType = NoticeConstants.TaskType.CASE_REVIEW_TASK, event = NoticeConstants.Event.CREATE, target = "#targetClass.getMainCaseReview(#request)", targetClass = CaseReviewNoticeService.class) @RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_ADD) - public void addCaseReview(@Validated @RequestBody CaseReviewAddRequest request) { + public void addCaseReview(@Validated @RequestBody CaseReviewRequest request) { caseReviewService.addCaseReview(request, SessionUtils.getUserId()); } + @PostMapping("/edit") + @Operation(summary = "用例管理-用例评审-编辑用例评审") + @Log(type = OperationLogType.UPDATE, expression = "#msClass.updateCaseReviewLog(#request)", msClass = CaseReviewLogService.class) + @SendNotice(taskType = NoticeConstants.TaskType.CASE_REVIEW_TASK, event = NoticeConstants.Event.UPDATE, target = "#targetClass.getMainCaseReview(#request)", targetClass = CaseReviewNoticeService.class) + @RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_UPDATE) + public void editCaseReview(@Validated({Updated.class}) @RequestBody CaseReviewRequest request) { + caseReviewService.editCaseReview(request, SessionUtils.getUserId()); + } + @PostMapping("/edit/follower") @Operation(summary = "用例管理-用例评审-关注/取消关注用例") @RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_UPDATE) @@ -41,4 +57,12 @@ public class CaseReviewController { caseReviewService.editFollower(request.getCaseReviewId(), SessionUtils.getUserId()); } + @GetMapping("/user-option/{projectId}") + @Operation(summary = "用例管理-用例评审-获取具有评审权限的用户") + @RequiresPermissions(value = {PermissionConstants.CASE_REVIEW_READ_ADD,PermissionConstants.CASE_REVIEW_READ_UPDATE}, logical = Logical.OR) + public List getReviewUserList(@PathVariable String projectId, @Schema(description = "查询关键字,根据邮箱和用户名查询") + @RequestParam(value = "keyword", required = false) String keyword) { + return caseReviewService.getReviewUserList(projectId, keyword); + } + } \ No newline at end of file diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.java b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.java index d435704a94..21d39dd509 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.java @@ -12,5 +12,5 @@ public interface ExtCaseReviewMapper { List checkCaseByModuleIds(@Param("moduleIds") List deleteIds); - + Long getPos(@Param("projectId") String projectId); } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.xml b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.xml index 36c311ed14..5edf32f96d 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.xml +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewMapper.xml @@ -14,4 +14,16 @@ + + \ No newline at end of file diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/request/CaseReviewAddRequest.java b/backend/services/case-management/src/main/java/io/metersphere/functional/request/CaseReviewRequest.java similarity index 85% rename from backend/services/case-management/src/main/java/io/metersphere/functional/request/CaseReviewAddRequest.java rename to backend/services/case-management/src/main/java/io/metersphere/functional/request/CaseReviewRequest.java index 144275ca42..d899397273 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/request/CaseReviewAddRequest.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/request/CaseReviewRequest.java @@ -1,5 +1,6 @@ package io.metersphere.functional.request; +import io.metersphere.validation.groups.Updated; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; @@ -12,11 +13,15 @@ import java.util.List; @Data @EqualsAndHashCode(callSuper = false) -public class CaseReviewAddRequest implements Serializable { +public class CaseReviewRequest implements Serializable { @Serial private static final long serialVersionUID = 1L; + @Schema(description = "用例id", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "{functional_case.id.not_blank}", groups = {Updated.class}) + private String id; + @Schema(description = "项目id", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank(message = "{case_review.project_id.not_blank}") private String projectId; diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewLogService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewLogService.java index e6e7e0eb22..8cc100025b 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewLogService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewLogService.java @@ -1,11 +1,14 @@ package io.metersphere.functional.service; -import io.metersphere.functional.request.CaseReviewAddRequest; +import io.metersphere.functional.domain.CaseReview; +import io.metersphere.functional.mapper.CaseReviewMapper; +import io.metersphere.functional.request.CaseReviewRequest; import io.metersphere.sdk.constants.HttpMethodConstants; import io.metersphere.sdk.util.JSON; import io.metersphere.system.log.constants.OperationLogModule; import io.metersphere.system.log.constants.OperationLogType; import io.metersphere.system.log.dto.LogDTO; +import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,13 +19,16 @@ import org.springframework.transaction.annotation.Transactional; @Transactional(rollbackFor = Exception.class) public class CaseReviewLogService { + @Resource + private CaseReviewMapper caseReviewMapper; + /** * 新增用例评审 日志 * * @param requests 页面参数 * @return LogDTO */ - public LogDTO addCaseReviewLog(CaseReviewAddRequest requests) { + public LogDTO addCaseReviewLog(CaseReviewRequest requests) { LogDTO dto = new LogDTO( requests.getProjectId(), null, @@ -37,4 +43,30 @@ public class CaseReviewLogService { dto.setOriginalValue(JSON.toJSONBytes(requests)); return dto; } + + /** + * 更新用例评审 日志 + * + * @param requests 页面参数 + * @return LogDTO + */ + public LogDTO updateCaseReviewLog(CaseReviewRequest requests) { + CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(requests.getId()); + if (caseReview ==null) { + return null; + } + LogDTO dto = new LogDTO( + caseReview.getProjectId(), + null, + caseReview.getId(), + caseReview.getCreateUser(), + OperationLogType.UPDATE.name(), + OperationLogModule.CASE_REVIEW, + caseReview.getName()); + + dto.setPath("/case/review/edit"); + dto.setMethod(HttpMethodConstants.POST.name()); + dto.setOriginalValue(JSON.toJSONBytes(caseReview)); + return dto; + } } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewNoticeService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewNoticeService.java new file mode 100644 index 0000000000..4824d68810 --- /dev/null +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewNoticeService.java @@ -0,0 +1,56 @@ +package io.metersphere.functional.service; + +import io.metersphere.functional.constants.CaseReviewStatus; +import io.metersphere.functional.domain.CaseReview; +import io.metersphere.functional.mapper.CaseReviewMapper; +import io.metersphere.functional.mapper.ExtCaseReviewMapper; +import io.metersphere.functional.request.CaseReviewRequest; +import io.metersphere.sdk.util.JSON; +import io.metersphere.system.utils.SessionUtils; +import jakarta.annotation.Resource; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +@Service +public class CaseReviewNoticeService { + + @Resource + private ExtCaseReviewMapper extCaseReviewMapper; + + @Resource + private CaseReviewMapper caseReviewMapper; + + public CaseReview getMainCaseReview(CaseReviewRequest request){ + CaseReview caseReview = null; + if (StringUtils.isNotBlank(request.getId())) { + caseReview = caseReviewMapper.selectByPrimaryKey(request.getId()); + } + if (caseReview == null) { + caseReview = new CaseReview(); + } + caseReview.setName(request.getName()); + caseReview.setModuleId(request.getModuleId()); + if (StringUtils.isBlank(request.getId())) { + caseReview.setProjectId(request.getProjectId()); + caseReview.setStatus(CaseReviewStatus.PREPARED.toString()); + caseReview.setReviewPassRule(request.getReviewPassRule()); + caseReview.setPos(getNextPos(request.getProjectId())); + caseReview.setCreateTime(System.currentTimeMillis()); + caseReview.setCreateUser(SessionUtils.getUserId()); + } + if (CollectionUtils.isNotEmpty(request.getTags())) { + caseReview.setTags(JSON.toJSONString(request.getTags())); + } + caseReview.setStartTime(request.getStartTime()); + caseReview.setEndTime(request.getEndTime()); + caseReview.setUpdateTime(System.currentTimeMillis()); + caseReview.setUpdateUser(SessionUtils.getUserId()); + return caseReview; + } + + public Long getNextPos(String projectId) { + Long pos = extCaseReviewMapper.getPos(projectId); + return (pos == null ? 0 : pos) + 5000; + } +} diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewService.java index c714f154b0..b0e3906055 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewService.java @@ -5,10 +5,13 @@ import io.metersphere.functional.constants.CaseReviewStatus; import io.metersphere.functional.constants.FunctionalCaseReviewStatus; import io.metersphere.functional.domain.*; import io.metersphere.functional.mapper.*; -import io.metersphere.functional.request.CaseReviewAddRequest; +import io.metersphere.functional.request.CaseReviewRequest; import io.metersphere.functional.result.CaseManagementResultCode; +import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.util.JSON; +import io.metersphere.system.domain.User; +import io.metersphere.system.mapper.ExtUserMapper; import io.metersphere.system.uid.IDGenerator; import jakarta.annotation.Resource; import org.apache.commons.collections4.CollectionUtils; @@ -19,6 +22,8 @@ import org.mybatis.spring.SqlSessionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; + /** * 用例评审表服务实现类 * @@ -28,16 +33,20 @@ import org.springframework.transaction.annotation.Transactional; @Transactional(rollbackFor = Exception.class) public class CaseReviewService { - public static final int ORDER_STEP = 5000; + public static final int POS_STEP = 5000; @Resource - private ExtFunctionalCaseMapper extFunctionalCaseMapper; + private ExtCaseReviewMapper extCaseReviewMapper; @Resource private CaseReviewMapper caseReviewMapper; @Resource private CaseReviewFollowerMapper caseReviewFollowerMapper; @Resource SqlSessionFactory sqlSessionFactory; + @Resource + private CaseReviewUserMapper caseReviewUserMapper; + @Resource + private ExtUserMapper extUserMapper; /** * 添加用例评审 @@ -45,7 +54,7 @@ public class CaseReviewService { * @param request 页面参数 * @param userId 当前操作人 */ - public void addCaseReview(CaseReviewAddRequest request, String userId) { + public void addCaseReview(CaseReviewRequest request, String userId) { String caseReviewId = IDGenerator.nextStr(); addCaseReview(request, userId, caseReviewId); SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); @@ -63,69 +72,39 @@ public class CaseReviewService { } /** - * 保存用例评审和功能用例的关系 - * @param request request + * 编辑用例评审 + * @param request 页面参数 * @param userId 当前操作人 - * @param caseReviewId 用例评审id - * @param caseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper */ - private void addCaseReviewFunctionalCase(CaseReviewAddRequest request, String userId, String caseReviewId, CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper) { - if (CollectionUtils.isNotEmpty(request.getCaseIds())) { - request.getReviewers().forEach(caseId -> { - CaseReviewFunctionalCase caseReviewFunctionalCase = new CaseReviewFunctionalCase(); - caseReviewFunctionalCase.setReviewId(caseReviewId); - caseReviewFunctionalCase.setCaseId(caseId); - caseReviewFunctionalCase.setStatus(FunctionalCaseReviewStatus.UN_REVIEWED.toString()); - caseReviewFunctionalCase.setCreateUser(userId); - caseReviewFunctionalCase.setCreateTime(System.currentTimeMillis()); - caseReviewFunctionalCase.setUpdateTime(System.currentTimeMillis()); - caseReviewFunctionalCase.setId(IDGenerator.nextStr()); - caseReviewFunctionalCase.setPos(getNextOrder(request.getProjectId())); - caseReviewFunctionalCaseMapper.insert(caseReviewFunctionalCase); - }); - } - } - - /** - * 保存用例评审和评审人的关系 - * @param request request - * @param caseReviewId 用例评审 - * @param caseReviewUserMapper caseReviewUserMapper - */ - private static void addCaseReviewUser(CaseReviewAddRequest request, String caseReviewId, CaseReviewUserMapper caseReviewUserMapper) { - request.getReviewers().forEach(user -> { - CaseReviewUser caseReviewUser = new CaseReviewUser(); - caseReviewUser.setReviewId(caseReviewId); - caseReviewUser.setUserId(user); - caseReviewUserMapper.insert(caseReviewUser); - }); - } - - /** - * 新增用例评审 - * @param request request - * @param userId 当前操作人 - * @param caseReviewId 用例评审id - */ - private void addCaseReview(CaseReviewAddRequest request, String userId, String caseReviewId) { + public void editCaseReview(CaseReviewRequest request, String userId) { + String reviewId = request.getId(); + checkCaseReview(reviewId); CaseReview caseReview = new CaseReview(); - caseReview.setId(caseReviewId); + caseReview.setId(reviewId); caseReview.setProjectId(request.getProjectId()); caseReview.setName(request.getName()); caseReview.setModuleId(request.getModuleId()); - caseReview.setStatus(CaseReviewStatus.PREPARED.toString()); - caseReview.setReviewPassRule(request.getReviewPassRule()); - caseReview.setPos(getNextOrder(request.getProjectId())); if (CollectionUtils.isNotEmpty(request.getTags())) { caseReview.setTags(JSON.toJSONString(request.getTags())); } caseReview.setStartTime(request.getStartTime()); caseReview.setEndTime(request.getEndTime()); - caseReview.setCreateTime(System.currentTimeMillis()); caseReview.setUpdateTime(System.currentTimeMillis()); - caseReview.setCreateUser(userId); caseReview.setUpdateUser(userId); - caseReviewMapper.insert(caseReview); + caseReviewMapper.updateByPrimaryKeySelective(caseReview); + //删除用例评审和评审人的关系 + CaseReviewUserExample caseReviewUserExample = new CaseReviewUserExample(); + caseReviewUserExample.createCriteria().andReviewIdEqualTo(reviewId); + caseReviewUserMapper.deleteByExample(caseReviewUserExample); + SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); + CaseReviewUserMapper mapper = sqlSession.getMapper(CaseReviewUserMapper.class); + try { + //保存评审和评审人的关系 + addCaseReviewUser(request, reviewId, mapper); + sqlSession.flushStatements(); + } finally { + SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); + } } /** @@ -148,26 +127,105 @@ public class CaseReviewService { } } + /** + * 获取具有评审权限的用户 + * @param projectId projectId + * @param keyword 查询关键字,根据邮箱和用户名查询 + * @return List + */ + public List getReviewUserList(String projectId, String keyword) { + return extUserMapper.getUserByPermission(projectId, keyword, PermissionConstants.CASE_REVIEW_REVIEW); + + } + + /** + * 新增用例评审 + * @param request request + * @param userId 当前操作人 + * @param caseReviewId 用例评审id + */ + private void addCaseReview(CaseReviewRequest request, String userId, String caseReviewId) { + CaseReview caseReview = new CaseReview(); + caseReview.setId(caseReviewId); + caseReview.setProjectId(request.getProjectId()); + caseReview.setName(request.getName()); + caseReview.setModuleId(request.getModuleId()); + caseReview.setStatus(CaseReviewStatus.PREPARED.toString()); + caseReview.setReviewPassRule(request.getReviewPassRule()); + caseReview.setPos(getNextPos(request.getProjectId())); + if (CollectionUtils.isNotEmpty(request.getTags())) { + caseReview.setTags(JSON.toJSONString(request.getTags())); + } + caseReview.setStartTime(request.getStartTime()); + caseReview.setEndTime(request.getEndTime()); + caseReview.setCreateTime(System.currentTimeMillis()); + caseReview.setUpdateTime(System.currentTimeMillis()); + caseReview.setCreateUser(userId); + caseReview.setUpdateUser(userId); + caseReviewMapper.insert(caseReview); + } + /** * 检查用例评审是否存在 * * @param caseReviewId 用例评审id - * @return CaseReview */ - private CaseReview checkCaseReview(String caseReviewId) { + private void checkCaseReview(String caseReviewId) { CaseReviewExample caseReviewExample = new CaseReviewExample(); caseReviewExample.createCriteria().andIdEqualTo(caseReviewId); CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(caseReviewId); if (caseReview == null) { throw new MSException(CaseManagementResultCode.CASE_REVIEW_NOT_FOUND); } - return caseReview; } - public Long getNextOrder(String projectId) { - Long pos = extFunctionalCaseMapper.getPos(projectId); - return (pos == null ? 0 : pos) + ORDER_STEP; + /** + * + * @param projectId 项目id + * @return pos + */ + public Long getNextPos(String projectId) { + Long pos = extCaseReviewMapper.getPos(projectId); + return (pos == null ? 0 : pos) + POS_STEP; } + /** + * 保存用例评审和功能用例的关系 + * @param request request + * @param userId 当前操作人 + * @param caseReviewId 用例评审id + * @param caseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper + */ + private void addCaseReviewFunctionalCase(CaseReviewRequest request, String userId, String caseReviewId, CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper) { + if (CollectionUtils.isNotEmpty(request.getCaseIds())) { + request.getReviewers().forEach(caseId -> { + CaseReviewFunctionalCase caseReviewFunctionalCase = new CaseReviewFunctionalCase(); + caseReviewFunctionalCase.setReviewId(caseReviewId); + caseReviewFunctionalCase.setCaseId(caseId); + caseReviewFunctionalCase.setStatus(FunctionalCaseReviewStatus.UN_REVIEWED.toString()); + caseReviewFunctionalCase.setCreateUser(userId); + caseReviewFunctionalCase.setCreateTime(System.currentTimeMillis()); + caseReviewFunctionalCase.setUpdateTime(System.currentTimeMillis()); + caseReviewFunctionalCase.setId(IDGenerator.nextStr()); + caseReviewFunctionalCase.setPos(getNextPos(request.getProjectId())); + caseReviewFunctionalCaseMapper.insert(caseReviewFunctionalCase); + }); + } + } + + /** + * 保存用例评审和评审人的关系 + * @param request request + * @param caseReviewId 用例评审 + * @param caseReviewUserMapper caseReviewUserMapper + */ + private static void addCaseReviewUser(CaseReviewRequest request, String caseReviewId, CaseReviewUserMapper caseReviewUserMapper) { + request.getReviewers().forEach(user -> { + CaseReviewUser caseReviewUser = new CaseReviewUser(); + caseReviewUser.setReviewId(caseReviewId); + caseReviewUser.setUserId(user); + caseReviewUserMapper.insert(caseReviewUser); + }); + } } \ No newline at end of file diff --git a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewControllerTests.java b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewControllerTests.java index 45a449e19c..6729f6708d 100644 --- a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewControllerTests.java +++ b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewControllerTests.java @@ -6,9 +6,16 @@ import io.metersphere.functional.mapper.CaseReviewFollowerMapper; import io.metersphere.functional.mapper.CaseReviewFunctionalCaseMapper; import io.metersphere.functional.mapper.CaseReviewMapper; import io.metersphere.functional.mapper.CaseReviewUserMapper; -import io.metersphere.functional.request.CaseReviewAddRequest; import io.metersphere.functional.request.CaseReviewFollowerRequest; +import io.metersphere.functional.request.CaseReviewRequest; +import io.metersphere.project.domain.Notification; +import io.metersphere.project.domain.NotificationExample; +import io.metersphere.project.mapper.NotificationMapper; +import io.metersphere.sdk.util.JSON; import io.metersphere.system.base.BaseTest; +import io.metersphere.system.controller.handler.ResultHolder; +import io.metersphere.system.domain.User; +import io.metersphere.system.notice.constants.NoticeConstants; import jakarta.annotation.Resource; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.*; @@ -17,8 +24,10 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -35,7 +44,10 @@ public class CaseReviewControllerTests extends BaseTest { private static final String projectId = "project-gyq-case-review-test"; private static final String ADD_CASE_REVIEW = "/case/review/add"; + private static final String EDIT_CASE_REVIEW = "/case/review/edit"; private static final String FOLLOW_CASE_REVIEW = "/case/review/edit/follower"; + private static final String CASE_REVIEWER_LIST = "/case/review/user-option/"; + @Resource private CaseReviewMapper caseReviewMapper; @@ -46,16 +58,16 @@ public class CaseReviewControllerTests extends BaseTest { private CaseReviewUserMapper caseReviewUserMapper; @Resource private CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper; + @Resource + private NotificationMapper notificationMapper; @Test @Order(1) @Sql(scripts = {"/dml/init_case_review.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED)) public void addCaseReviewSuccess() throws Exception { - CaseReviewAddRequest caseReviewAddRequest = getCaseReviewAddRequest("创建评审1", CaseReviewPassRule.SINGLE.toString(), "CASE_REVIEW_TEST_GYQ_ID", false, true); - this.requestPostWithOk(ADD_CASE_REVIEW,caseReviewAddRequest); - CaseReviewExample caseReviewExample = new CaseReviewExample(); - caseReviewExample.createCriteria().andNameEqualTo("创建评审1"); - List caseReviews = caseReviewMapper.selectByExample(caseReviewExample); + CaseReviewRequest caseReviewRequest = getCaseReviewAddRequest("创建评审1", CaseReviewPassRule.SINGLE.toString(), "CASE_REVIEW_TEST_GYQ_ID", false, true, null); + this.requestPostWithOk(ADD_CASE_REVIEW, caseReviewRequest); + List caseReviews = getCaseReviews("创建评审1"); Assertions.assertEquals(1, caseReviews.size()); String caseReviewId = caseReviews.get(0).getId(); CaseReviewUserExample caseReviewUserExample = new CaseReviewUserExample(); @@ -66,41 +78,54 @@ public class CaseReviewControllerTests extends BaseTest { caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(caseReviewId); List caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample); Assertions.assertEquals(1, caseReviewFunctionalCases.size()); + NotificationExample notificationExample = new NotificationExample(); + notificationExample.createCriteria().andResourceTypeEqualTo(NoticeConstants.TaskType.CASE_REVIEW_TASK); + List notifications = notificationMapper.selectByExampleWithBLOBs(notificationExample); + System.out.println(JSON.toJSONString(notifications)); + Assertions.assertEquals(1, notifications.size()); + + } + + private List getCaseReviews(String name) { + CaseReviewExample caseReviewExample = new CaseReviewExample(); + caseReviewExample.createCriteria().andNameEqualTo(name); + return caseReviewMapper.selectByExample(caseReviewExample); } @NotNull - private static CaseReviewAddRequest getCaseReviewAddRequest(String name, String reviewPassRule, String caseId, boolean tag, boolean reviewer) { - CaseReviewAddRequest caseReviewAddRequest = new CaseReviewAddRequest(); - caseReviewAddRequest.setProjectId(projectId); - caseReviewAddRequest.setName(name); - caseReviewAddRequest.setModuleId("CASE_REVIEW_REAL_MODULE_ID"); - caseReviewAddRequest.setReviewPassRule(reviewPassRule); + private static CaseReviewRequest getCaseReviewAddRequest(String name, String reviewPassRule, String caseId, boolean tag, boolean reviewer, String id) { + CaseReviewRequest caseReviewRequest = new CaseReviewRequest(); + if (StringUtils.isNotBlank(id)) { + caseReviewRequest.setId(id); + } + caseReviewRequest.setProjectId(projectId); + caseReviewRequest.setName(name); + caseReviewRequest.setModuleId("CASE_REVIEW_REAL_MODULE_ID"); + caseReviewRequest.setReviewPassRule(reviewPassRule); List reviewers = new ArrayList<>(); reviewers.add("admin"); if (reviewer) { - caseReviewAddRequest.setReviewers(reviewers); + caseReviewRequest.setReviewers(reviewers); } if (StringUtils.isNotBlank(caseId)) { List caseIds = new ArrayList<>(); caseIds.add(caseId); - caseReviewAddRequest.setCaseIds(caseIds); + caseReviewRequest.setCaseIds(caseIds); } if (tag) { List tags = new ArrayList<>(); tags.add("11"); - caseReviewAddRequest.setTags(tags); + caseReviewRequest.setTags(tags); } - return caseReviewAddRequest; + return caseReviewRequest; } @Test @Order(2) public void addCaseReviewWidthOutCaseIdsSuccess() throws Exception { - CaseReviewAddRequest caseReviewAddRequest = getCaseReviewAddRequest("创建评审2", CaseReviewPassRule.SINGLE.toString(), null, false, true); - this.requestPostWithOk(ADD_CASE_REVIEW,caseReviewAddRequest); - CaseReviewExample caseReviewExample = new CaseReviewExample(); - caseReviewExample.createCriteria().andNameEqualTo("创建评审2"); - List caseReviews = caseReviewMapper.selectByExample(caseReviewExample); + CaseReviewRequest caseReviewRequest = getCaseReviewAddRequest("创建评审2", CaseReviewPassRule.SINGLE.toString(), null, false, true, null); + this.requestPostWithOk(ADD_CASE_REVIEW, caseReviewRequest); + List caseReviews = getCaseReviews("创建评审2"); Assertions.assertEquals(1, caseReviews.size()); String caseReviewId = caseReviews.get(0).getId(); CaseReviewUserExample caseReviewUserExample = new CaseReviewUserExample(); @@ -113,14 +138,13 @@ public class CaseReviewControllerTests extends BaseTest { Assertions.assertEquals(0, caseReviewFunctionalCases.size()); } + @Test @Order(3) public void addCaseReviewWidthTagsSuccess() throws Exception { - CaseReviewAddRequest caseReviewAddRequest = getCaseReviewAddRequest("创建评审3", CaseReviewPassRule.SINGLE.toString(), null, true, true); - this.requestPostWithOk(ADD_CASE_REVIEW,caseReviewAddRequest); - CaseReviewExample caseReviewExample = new CaseReviewExample(); - caseReviewExample.createCriteria().andNameEqualTo("创建评审3"); - List caseReviews = caseReviewMapper.selectByExample(caseReviewExample); + CaseReviewRequest caseReviewRequest = getCaseReviewAddRequest("创建评审3", CaseReviewPassRule.SINGLE.toString(), null, true, true, null); + this.requestPostWithOk(ADD_CASE_REVIEW, caseReviewRequest); + List caseReviews = getCaseReviews("创建评审3"); Assertions.assertEquals(1, caseReviews.size()); String caseReviewId = caseReviews.get(0).getId(); Assertions.assertNotNull(caseReviews.get(0).getTags()); @@ -137,18 +161,16 @@ public class CaseReviewControllerTests extends BaseTest { @Test @Order(4) public void addCaseReviewFalse() throws Exception { - CaseReviewAddRequest caseReviewAddRequestNoReviewer= getCaseReviewAddRequest("创建评审4", CaseReviewPassRule.SINGLE.toString(), null, true, false); - this.requestPost(ADD_CASE_REVIEW, caseReviewAddRequestNoReviewer).andExpect(status().is4xxClientError()); - CaseReviewAddRequest caseReviewAddRequestNoName = getCaseReviewAddRequest(null, CaseReviewPassRule.SINGLE.toString(), null, true, true); - this.requestPost(ADD_CASE_REVIEW, caseReviewAddRequestNoName).andExpect(status().is4xxClientError()); + CaseReviewRequest caseReviewRequestNoReviewer = getCaseReviewAddRequest("创建评审4", CaseReviewPassRule.SINGLE.toString(), null, true, false, null); + this.requestPost(ADD_CASE_REVIEW, caseReviewRequestNoReviewer).andExpect(status().is4xxClientError()); + CaseReviewRequest caseReviewRequestNoName = getCaseReviewAddRequest(null, CaseReviewPassRule.SINGLE.toString(), null, true, true, null); + this.requestPost(ADD_CASE_REVIEW, caseReviewRequestNoName).andExpect(status().is4xxClientError()); } @Test @Order(5) public void followCaseReview() throws Exception { - CaseReviewExample caseReviewExample = new CaseReviewExample(); - caseReviewExample.createCriteria().andNameEqualTo("创建评审1"); - List caseReviews = caseReviewMapper.selectByExample(caseReviewExample); + List caseReviews = getCaseReviews("创建评审1"); CaseReview caseReview = caseReviews.get(0); CaseReviewFollowerRequest caseReviewFollowerRequest = new CaseReviewFollowerRequest(); caseReviewFollowerRequest.setCaseReviewId(caseReview.getId()); @@ -176,5 +198,49 @@ public class CaseReviewControllerTests extends BaseTest { this.requestPost(FOLLOW_CASE_REVIEW, caseReviewFollowerRequest).andExpect(status().is5xxServerError()); } + @Test + @Order(7) + public void editCaseReviewSuccess() throws Exception { + List caseReviews = getCaseReviews("创建评审1"); + CaseReview caseReview = caseReviews.get(0); + CaseReviewRequest caseReviewRequest = getCaseReviewAddRequest("创建评审更新1", CaseReviewPassRule.SINGLE.toString(), null, true, true, caseReview.getId()); + this.requestPostWithOk(EDIT_CASE_REVIEW, caseReviewRequest); + List updateCaseReviews = getCaseReviews("创建评审更新1"); + Assertions.assertEquals(1, updateCaseReviews.size()); + + List caseReviews2 = getCaseReviews("创建评审2"); + CaseReview caseReview2 = caseReviews2.get(0); + CaseReviewRequest caseReviewRequest2 = getCaseReviewAddRequest("创建评审更新2", CaseReviewPassRule.SINGLE.toString(), null, false, true, caseReview2.getId()); + this.requestPostWithOk(EDIT_CASE_REVIEW, caseReviewRequest2); + List updateCaseReviews2 = getCaseReviews("创建评审更新2"); + Assertions.assertEquals(1, updateCaseReviews2.size()); + + NotificationExample notificationExample = new NotificationExample(); + notificationExample.createCriteria().andResourceTypeEqualTo(NoticeConstants.TaskType.CASE_REVIEW_TASK).andReceiverEqualTo("gyq_review_test2"); + List notifications = notificationMapper.selectByExampleWithBLOBs(notificationExample); + System.out.println(JSON.toJSONString(notifications)); + Assertions.assertTrue(notifications.size()>0); + + } + + @Test + @Order(8) + public void editCaseReviewFalse() throws Exception { + CaseReviewRequest caseReviewRequest = getCaseReviewAddRequest("创建评审更新1", CaseReviewPassRule.SINGLE.toString(), null, true, true, null); + this.requestPost(EDIT_CASE_REVIEW, caseReviewRequest).andExpect(status().is4xxClientError()); + caseReviewRequest = getCaseReviewAddRequest("创建评审更新1", CaseReviewPassRule.SINGLE.toString(), null, true, true, "XXX"); + this.requestPost(EDIT_CASE_REVIEW, caseReviewRequest).andExpect(status().is5xxServerError()); + } + + @Test + @Order(9) + public void getUserList() throws Exception { + MvcResult mvcResult = this.requestGetWithOkAndReturn(CASE_REVIEWER_LIST + projectId); + String contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class); + List list = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), User.class); + Assertions.assertFalse(list.isEmpty()); + } + } diff --git a/backend/services/case-management/src/test/resources/dml/init_case_review.sql b/backend/services/case-management/src/test/resources/dml/init_case_review.sql index d888aab733..896041e110 100644 --- a/backend/services/case-management/src/test/resources/dml/init_case_review.sql +++ b/backend/services/case-management/src/test/resources/dml/init_case_review.sql @@ -29,3 +29,56 @@ INSERT INTO functional_case_module(id, project_id, name, parent_id, pos, create_ INSERT INTO case_review_module(id, project_id, name, parent_id, pos, create_time, update_time, create_user, update_user) VALUES ('CASE_REVIEW_REAL_MODULE_ID', 'project-gyq-case-review-test', '用例评审所属模块', 'NONE', 0, 1669174143999, 1669174143999, 'admin', 'admin'); +INSERT INTO user(id, name, email, password, create_time, update_time, language, last_organization_id, phone, source, + last_project_id, create_user, update_user, deleted) +VALUES ('gyq_review_test', 'gyq_review_test', 'PROJECT@fit2cloud.com', MD5('metersphere'),UNIX_TIMESTAMP() * 1000,UNIX_TIMESTAMP() * 1000, NULL, NUll, '', 'LOCAL', NULL, 'admin', 'admin', false), + ('gyq_review_test2', 'default-Administrator-1', 'admin-default-user@metersphere.io', MD5('metersphere'), UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, NULL, NUll, '', 'LOCAL', NULL, 'admin', 'admin', false); + + +INSERT INTO user_role(id, name, description, internal, type, create_time, update_time, create_user, scope_id) VALUE + ('review-case-role-id-1', 'review-case-role-1', 'XXX', FALSE, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'project-gyq-case-review-test'); +INSERT INTO user_role(id, name, description, internal, type, create_time, update_time, create_user, scope_id) VALUE + ('review-case-role-id-2', 'review-case-role-2', 'XXX', FALSE, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'project-gyq-case-review-test'); +INSERT INTO user_role(id, name, description, internal, type, create_time, update_time, create_user, scope_id) VALUE + ('review-case-role-id-3', 'review-case-role-3', 'XXX', FALSE, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'project-gyq-case-review-test'); +INSERT INTO user_role(id, name, description, internal, type, create_time, update_time, create_user, scope_id) VALUE + ('review-case-role-id-4', 'review-case-role-4', 'XXX', FALSE, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'project-gyq-case-review-test'); + +INSERT INTO user_role_permission (id, role_id, permission_id) VALUE + (uuid(), 'review-case-role-id-3', 'CASE_REVIEW:READ+REVIEW'); +INSERT INTO user_role_relation (id, user_id, role_id, source_id, organization_id, create_time, create_user) VALUE + (UUID(), 'gyq_review_test', 'review-case-role-id-3', 'project-gyq-case-review-test', 'organization-gyq-case-review-test', UNIX_TIMESTAMP() * 1000, 'admin'); +INSERT INTO user_role_relation (id, user_id, role_id, source_id, organization_id, create_time, create_user) VALUE + (UUID(), 'gyq_review_test2', 'review-case-role-id-3', 'project-gyq-case-review-test', 'organization-gyq-case-review-test', UNIX_TIMESTAMP() * 1000, 'admin'); + + + +INSERT INTO project_robot(id, project_id, name, platform, webhook, type, app_key, app_secret, enable, create_user, create_time, update_user, update_time, description) VALUES ('test_case_review_message_robot1', 'project-gyq-case-review-test', '测试机器人1', 'IN_SITE', 'NONE', null, null, null, true, 'admin', unix_timestamp() * 1000,'admin', unix_timestamp() * 1000, null); + + +Insert into message_task(id, event, receiver, project_robot_id, task_type, test_id, project_id, enable, create_user, create_time, update_user, update_time, use_default_template, use_default_subject, subject) +VALUES ('case-review_message0', 'CREATE', 'gyq_review_test', 'test_case_review_message_robot1', 'CASE_REVIEW_TASK', 'NONE', 'project-gyq-case-review-test', true, 'admin', unix_timestamp() * 1000, 'admin', unix_timestamp() * 1000, true, true, 'message.title.case_review_task_create'); +INSERT INTO message_task_blob(id, template) VALUES ('case-review_message0', 'message.case_review_task_create'); + +Insert into message_task(id, event, receiver, project_robot_id, task_type, test_id, project_id, enable, create_user, create_time, update_user, update_time, use_default_template, use_default_subject, subject) +VALUES ('case-review_message1', 'UPDATE', 'CREATE_USER', 'test_case_review_message_robot1', 'CASE_REVIEW_TASK', 'NONE', 'project-gyq-case-review-test', true, 'admin', unix_timestamp() * 1000, 'admin', unix_timestamp() * 1000, true, true, 'message.title.case_review_task_update'); +INSERT INTO message_task_blob(id, template) VALUES ('case-review_message1', 'message.case_review_task_update'); + + +Insert into message_task(id, event, receiver, project_robot_id, task_type, test_id, project_id, enable, create_user, create_time, update_user, update_time, use_default_template, use_default_subject, subject) +VALUES ('case-review_message2', 'UPDATE', 'FOLLOW_PEOPLE', 'test_case_review_message_robot1', 'CASE_REVIEW_TASK', 'NONE', 'project-gyq-case-review-test', true, 'admin', unix_timestamp() * 1000, 'admin', unix_timestamp() * 1000, true, true, 'message.title.case_review_task_update'); +INSERT INTO message_task_blob(id, template) VALUES ('case-review_message2', 'message.case_review_task_update'); + +Insert into message_task(id, event, receiver, project_robot_id, task_type, test_id, project_id, enable, create_user, create_time, update_user, update_time, use_default_template, use_default_subject, subject) +VALUES ('case-review_message5', 'UPDATE', 'gyq_review_test2', 'test_case_review_message_robot1', 'CASE_REVIEW_TASK', 'NONE', 'project-gyq-case-review-test', true, 'admin', unix_timestamp() * 1000, 'admin', unix_timestamp() * 1000, true, true, 'message.title.case_review_task_update'); +INSERT INTO message_task_blob(id, template) VALUES ('case-review_message5', 'message.case_review_task_update'); + +Insert into message_task(id, event, receiver, project_robot_id, task_type, test_id, project_id, enable, create_user, create_time, update_user, update_time, use_default_template, use_default_subject, subject) +VALUES ('case-review_message3', 'DELETE', 'CREATE_USER', 'test_case_review_message_robot1', 'CASE_REVIEW_TASK', 'NONE', 'project-gyq-case-review-test', true, 'admin', unix_timestamp() * 1000, 'admin', unix_timestamp() * 1000, true, true, 'message.title.case_review_task_delete'); +INSERT INTO message_task_blob(id, template) VALUES ('case-review_message3', 'message.case_review_task_delete'); + + +Insert into message_task(id, event, receiver, project_robot_id, task_type, test_id, project_id, enable, create_user, create_time, update_user, update_time, use_default_template, use_default_subject, subject) +VALUES ('case-review_message4', 'REVIEW_COMPLETED', 'CREATE_USER', 'test_case_review_message_robot1', 'CASE_REVIEW_TASK', 'NONE', 'project-gyq-case-review-test', true, 'admin', unix_timestamp() * 1000, 'admin', unix_timestamp() * 1000, true, true, 'message.title.case_review_task_review_completed'); +INSERT INTO message_task_blob(id, template) VALUES ('case-review_message4', 'message.case_review_task_review_completed'); + diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtUserMapper.java b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtUserMapper.java index c67d5c337f..21f113836a 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtUserMapper.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtUserMapper.java @@ -22,4 +22,13 @@ public interface ExtUserMapper { * @return 用户列表 */ List getRoleUserByParam(@Param("ids") List ids, @Param("keyword") String keyword); + + /** + * 获取某个项目下的固定权限的用户列表 + * @param projectId 项目ID + * @param keyword 关键字 + * @param permission 权限 + * @return 用户列表 + */ + ListgetUserByPermission(@Param("projectId") String projectId, @Param("keyword") String keyword, @Param("permission") String permission); } diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtUserMapper.xml b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtUserMapper.xml index 2f5a26a388..975e6efd1c 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtUserMapper.xml +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/ExtUserMapper.xml @@ -56,4 +56,19 @@ limit 100 + + + + \ No newline at end of file