Commit 04a05af1c1d0f15758bf4cbe84d1bce4827d31f3

Authored by YunaiV
1 parent 9d5d8c95

fix(pms): 过滤知识库文档已删除标签并保留历史编号

yudao-module-pms/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/kb/content/PmsKnowledgeDocumentController.java
... ... @@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.pms.dal.dataobject.kb.library.PmsKnowledgeLibrary
16 16 import cn.iocoder.yudao.module.pms.enums.kb.content.PmsKnowledgeContentLevelEnum;
17 17 import cn.iocoder.yudao.module.pms.enums.kb.content.PmsKnowledgeDocumentTypeEnum;
18 18 import cn.iocoder.yudao.module.pms.service.kb.content.PmsKnowledgeContentPermissionService;
  19 +import cn.iocoder.yudao.module.pms.service.kb.content.PmsKnowledgeDocumentLabelService;
19 20 import cn.iocoder.yudao.module.pms.service.kb.content.PmsKnowledgeDocumentService;
20 21 import cn.iocoder.yudao.module.pms.service.kb.interaction.PmsKnowledgeDocumentLikeService;
21 22 import cn.iocoder.yudao.module.pms.service.kb.interaction.PmsKnowledgeFavoriteService;
... ... @@ -47,6 +48,7 @@ import java.util.Set;
47 48 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
48 49 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
49 50 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  51 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
50 52 import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
51 53 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
52 54  
... ... @@ -61,6 +63,8 @@ public class PmsKnowledgeDocumentController {
61 63 @Resource
62 64 private PmsKnowledgeContentPermissionService contentPermissionService;
63 65 @Resource
  66 + private PmsKnowledgeDocumentLabelService documentLabelService;
  67 + @Resource
64 68 private PmsKnowledgeFavoriteService favoriteService;
65 69 @Resource
66 70 private PmsKnowledgeDocumentLikeService documentLikeService;
... ... @@ -150,6 +154,9 @@ public class PmsKnowledgeDocumentController {
150 154 && Boolean.FALSE.equals(documentVO.getDownloadStatus())) {
151 155 documentVO.setContent(null);
152 156 }
  157 + // 1.3 忽略已删除的标签编号,避免编辑回显后保存被拒:https://github.com/YunaiV/ruoyi-vue-pro/issues/1275
  158 + Set<Long> existLabelIds = documentLabelService.getDocumentLabelMap(document.getLabelIds()).keySet();
  159 + documentVO.setLabelIds(filterList(document.getLabelIds(), existLabelIds::contains));
153 160  
154 161 // 2. 一次查询并拼接创建人和点赞用户信息
155 162 List<PmsKnowledgeDocumentLikeDO> likes = documentLikeService.getDocumentLikeList(document.getId());
... ...
yudao-module-pms/src/main/java/cn/iocoder/yudao/module/pms/service/kb/content/PmsKnowledgeDocumentLabelService.java
... ... @@ -8,6 +8,9 @@ import cn.iocoder.yudao.module.pms.dal.dataobject.kb.content.PmsKnowledgeDocumen
8 8  
9 9 import java.util.Collection;
10 10 import java.util.List;
  11 +import java.util.Map;
  12 +
  13 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
11 14  
12 15 /**
13 16 * PMS 知识库文档标签 Service 接口
... ... @@ -54,6 +57,24 @@ public interface PmsKnowledgeDocumentLabelService {
54 57 List<PmsKnowledgeDocumentLabelDO> getDocumentLabelList();
55 58  
56 59 /**
  60 + * 获得文档标签列表
  61 + *
  62 + * @param ids 标签编号集合
  63 + * @return 标签列表
  64 + */
  65 + List<PmsKnowledgeDocumentLabelDO> getDocumentLabelList(Collection<Long> ids);
  66 +
  67 + /**
  68 + * 获得文档标签 Map
  69 + *
  70 + * @param ids 标签编号集合
  71 + * @return 文档标签 Map
  72 + */
  73 + default Map<Long, PmsKnowledgeDocumentLabelDO> getDocumentLabelMap(Collection<Long> ids) {
  74 + return convertMap(getDocumentLabelList(ids), PmsKnowledgeDocumentLabelDO::getId);
  75 + }
  76 +
  77 + /**
57 78 * 校验文档标签均存在
58 79 *
59 80 * @param ids 标签编号集合
... ...
yudao-module-pms/src/main/java/cn/iocoder/yudao/module/pms/service/kb/content/PmsKnowledgeDocumentLabelServiceImpl.java
... ... @@ -17,6 +17,7 @@ import org.springframework.stereotype.Service;
17 17 import org.springframework.validation.annotation.Validated;
18 18  
19 19 import java.util.Collection;
  20 +import java.util.Collections;
20 21 import java.util.HashSet;
21 22 import java.util.List;
22 23 import java.util.Set;
... ... @@ -82,6 +83,14 @@ public class PmsKnowledgeDocumentLabelServiceImpl implements PmsKnowledgeDocumen
82 83 }
83 84  
84 85 @Override
  86 + public List<PmsKnowledgeDocumentLabelDO> getDocumentLabelList(Collection<Long> ids) {
  87 + if (CollUtil.isEmpty(ids)) {
  88 + return Collections.emptyList();
  89 + }
  90 + return documentLabelMapper.selectByIds(ids);
  91 + }
  92 +
  93 + @Override
85 94 public void validateDocumentLabelList(Collection<Long> ids) {
86 95 if (CollUtil.isEmpty(ids)) {
87 96 return;
... ...
yudao-module-pms/src/test/java/cn/iocoder/yudao/module/pms/service/kb/content/PmsKnowledgeDocumentLabelServiceImplTest.java
... ... @@ -21,6 +21,7 @@ import java.util.Arrays;
21 21 import java.util.Collections;
22 22 import java.util.HashSet;
23 23 import java.util.List;
  24 +import java.util.Map;
24 25  
25 26 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
26 27 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
... ... @@ -28,6 +29,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
28 29 import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstants.KNOWLEDGE_DOCUMENT_LABEL_NOT_EXISTS;
29 30 import static org.junit.jupiter.api.Assertions.assertEquals;
30 31 import static org.junit.jupiter.api.Assertions.assertNull;
  32 +import static org.junit.jupiter.api.Assertions.assertTrue;
31 33 import static org.mockito.Mockito.when;
32 34  
33 35 /**
... ... @@ -91,6 +93,68 @@ public class PmsKnowledgeDocumentLabelServiceImplTest extends BaseDbUnitTest {
91 93 }
92 94  
93 95 @Test
  96 + public void testDeleteDocumentLabel_keepDocumentLabelIds() {
  97 + // mock 数据
  98 + PmsKnowledgeDocumentLabelDO deletedLabel = randomDocumentLabelDO();
  99 + documentLabelMapper.insert(deletedLabel);
  100 + PmsKnowledgeDocumentLabelDO otherLabel = randomDocumentLabelDO();
  101 + documentLabelMapper.insert(otherLabel);
  102 + PmsKnowledgeDocumentDO document = randomDocumentDO(randomLongId(),
  103 + Arrays.asList(deletedLabel.getId(), otherLabel.getId()));
  104 + documentMapper.insert(document);
  105 +
  106 + // 调用
  107 + documentLabelService.deleteDocumentLabel(deletedLabel.getId());
  108 +
  109 + // 断言:删除标签不改写文档,历史编号在详情读取时忽略
  110 + assertEquals(Arrays.asList(deletedLabel.getId(), otherLabel.getId()),
  111 + documentMapper.selectById(document.getId()).getLabelIds());
  112 + }
  113 +
  114 + @Test
  115 + public void testGetDocumentLabelList_ignoreDeleted() {
  116 + // mock 数据
  117 + PmsKnowledgeDocumentLabelDO label = randomDocumentLabelDO();
  118 + documentLabelMapper.insert(label);
  119 + PmsKnowledgeDocumentLabelDO deletedLabel = randomDocumentLabelDO();
  120 + documentLabelMapper.insert(deletedLabel);
  121 + documentLabelMapper.deleteById(deletedLabel.getId());
  122 +
  123 + // 调用
  124 + List<PmsKnowledgeDocumentLabelDO> list = documentLabelService.getDocumentLabelList(
  125 + Arrays.asList(label.getId(), deletedLabel.getId()));
  126 + Map<Long, PmsKnowledgeDocumentLabelDO> map = documentLabelService.getDocumentLabelMap(
  127 + Arrays.asList(label.getId(), deletedLabel.getId()));
  128 +
  129 + // 断言
  130 + assertEquals(1, list.size());
  131 + assertEquals(label.getId(), list.get(0).getId());
  132 + assertEquals(Collections.singleton(label.getId()), map.keySet());
  133 + }
  134 +
  135 + @Test
  136 + public void testGetDocumentLabelList_empty() {
  137 + // 调用,并断言
  138 + assertTrue(documentLabelService.getDocumentLabelList(null).isEmpty());
  139 + assertTrue(documentLabelService.getDocumentLabelList(Collections.emptyList()).isEmpty());
  140 + assertTrue(documentLabelService.getDocumentLabelMap(null).isEmpty());
  141 + }
  142 +
  143 + @Test
  144 + public void testValidateDocumentLabelList_deleted() {
  145 + // mock 数据
  146 + PmsKnowledgeDocumentLabelDO label = randomDocumentLabelDO();
  147 + documentLabelMapper.insert(label);
  148 + PmsKnowledgeDocumentLabelDO deletedLabel = randomDocumentLabelDO();
  149 + documentLabelMapper.insert(deletedLabel);
  150 + documentLabelMapper.deleteById(deletedLabel.getId());
  151 +
  152 + // 调用,并断言异常
  153 + assertServiceException(() -> documentLabelService.validateDocumentLabelList(
  154 + Arrays.asList(label.getId(), deletedLabel.getId())), KNOWLEDGE_DOCUMENT_LABEL_NOT_EXISTS);
  155 + }
  156 +
  157 + @Test
94 158 public void testGetDocumentLabel_success() {
95 159 // mock 数据
96 160 PmsKnowledgeDocumentLabelDO documentLabel = randomDocumentLabelDO();
... ...
yudao-module-pms/src/test/java/cn/iocoder/yudao/module/pms/service/kb/content/PmsKnowledgeDocumentServiceImplTest.java
... ... @@ -37,9 +37,11 @@ import java.util.Arrays;
37 37 import java.util.Collections;
38 38 import java.util.Map;
39 39  
  40 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
40 41 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
41 42 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
42 43 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  44 +import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstants.KNOWLEDGE_DOCUMENT_LABEL_NOT_EXISTS;
43 45 import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstants.KNOWLEDGE_DOCUMENT_MOVE_INVALID;
44 46 import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstants.KNOWLEDGE_DOCUMENT_MOVE_TARGET_INVALID;
45 47 import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstants.KNOWLEDGE_DOCUMENT_NOT_EXISTS;
... ... @@ -47,6 +49,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
47 49 import static org.junit.jupiter.api.Assertions.assertTrue;
48 50 import static org.mockito.ArgumentMatchers.anyCollection;
49 51 import static org.mockito.ArgumentMatchers.eq;
  52 +import static org.mockito.Mockito.doThrow;
50 53 import static org.mockito.Mockito.verify;
51 54 import static org.mockito.Mockito.when;
52 55  
... ... @@ -205,6 +208,29 @@ public class PmsKnowledgeDocumentServiceImplTest extends BaseDbUnitTest {
205 208 }
206 209  
207 210 @Test
  211 + public void testUpdateDocument_labelNotExists() {
  212 + // mock 数据:文档关联的旧标签已被删除
  213 + Long userId = randomLongId();
  214 + PmsKnowledgeLibraryDO library = randomLibraryDO();
  215 + libraryMapper.insert(library);
  216 + PmsKnowledgeDocumentDO document = randomDocumentDO(library.getId(), 0L, 0L)
  217 + .setContent("旧正文").setLabelIds(Arrays.asList(1L, 2L));
  218 + documentMapper.insert(document);
  219 + doThrow(exception(KNOWLEDGE_DOCUMENT_LABEL_NOT_EXISTS)).when(documentLabelService)
  220 + .validateDocumentLabelList(eq(Arrays.asList(1L, 2L)));
  221 + // 准备参数:原样提交旧标签
  222 + PmsKnowledgeDocumentUpdateReqVO reqVO = new PmsKnowledgeDocumentUpdateReqVO()
  223 + .setId(document.getId()).setContent("新正文").setLabelIds(Arrays.asList(1L, 2L));
  224 +
  225 + // 调用,并断言异常
  226 + assertServiceException(() -> documentService.updateDocument(reqVO, userId), KNOWLEDGE_DOCUMENT_LABEL_NOT_EXISTS);
  227 + // 断言:文档未被修改
  228 + PmsKnowledgeDocumentDO dbDocument = documentMapper.selectById(document.getId());
  229 + assertEquals("旧正文", dbDocument.getContent());
  230 + assertEquals(Arrays.asList(1L, 2L), dbDocument.getLabelIds());
  231 + }
  232 +
  233 + @Test
208 234 public void testDeleteDocument_recursive() {
209 235 // mock 数据
210 236 Long userId = randomLongId();
... ...