feat(B2): 附件引用模型-cms_attachment 增 ref_type/ref_id,消灭孤儿误报
- 实体/双 SQL 加列+idx_att_ref;upload 增 scene 白名单(banner/link/site) - AttachmentService 新增 markUsed/release/markSiteConfigUsed(webUrl 反查,幂等) - 未使用=articleId 与 refType 均空;page 返回 unusedCount(前后端同步改名无兼容别名) - Banner/Link 保存先解引用再回写(换图旧图回未使用);Site 配置 logo/favicon 引用回写(@Lazy 解循环依赖) - 新增13例(Attachment6/Banner3/Link2/Site2)+既有语义断言更新;mvn -o test 全绿
This commit is contained in:
@@ -136,4 +136,72 @@ class LinkServiceIT extends CmsIntegrationTestBase {
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("不存在");
|
||||
}
|
||||
|
||||
// ===== B2 附件引用模型(友链 logo 引用回写)=====
|
||||
|
||||
@Autowired
|
||||
private AttachmentService attachmentService;
|
||||
|
||||
/** 1x1 真实 png(上传需过魔数校验) */
|
||||
private org.springframework.mock.web.MockMultipartFile pngFile() {
|
||||
java.awt.image.BufferedImage img = new java.awt.image.BufferedImage(1, 1, java.awt.image.BufferedImage.TYPE_INT_RGB);
|
||||
java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
|
||||
try {
|
||||
javax.imageio.ImageIO.write(img, "png", out);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
return new org.springframework.mock.web.MockMultipartFile("file", "logo.png", "image/png", out.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("B2: 保存友链回写 attachment.ref_type=link, ref_id=linkId;删除解引用")
|
||||
void save_writesAttachmentRef_deleteReleases() {
|
||||
com.yunhai.cms.model.vo.AttachmentVo logo = attachmentService.upload(
|
||||
TestUsers.superAdmin(), siteId, null, "link", pngFile());
|
||||
|
||||
LinkSaveRequest r = req("带Logo友链", "https://www.example.com");
|
||||
r.setLogoUrl(logo.getUrl());
|
||||
LinkVo vo = linkService.save(TestUsers.superAdmin(), r);
|
||||
|
||||
com.yunhai.cms.entity.CmsAttachment att = attachmentRepository.findById(logo.getId())
|
||||
.orElseThrow(IllegalStateException::new);
|
||||
assertThat(att.getRefType()).isEqualTo("link");
|
||||
assertThat(att.getRefId()).isEqualTo(vo.getId());
|
||||
|
||||
DeleteRequest del = new DeleteRequest();
|
||||
del.setSiteId(siteId);
|
||||
del.setId(vo.getId());
|
||||
linkService.delete(TestUsers.superAdmin(), del);
|
||||
|
||||
com.yunhai.cms.entity.CmsAttachment released = attachmentRepository.findById(logo.getId())
|
||||
.orElseThrow(IllegalStateException::new);
|
||||
assertThat(released.getRefType()).isNull();
|
||||
assertThat(released.getRefId()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("B2: 友链无 logo 不产生附件引用;logo 清空后引用解除")
|
||||
void save_withoutLogo_noRef() {
|
||||
LinkSaveRequest r = req("纯文字友链", "https://www.example.com");
|
||||
LinkVo vo = linkService.save(TestUsers.superAdmin(), r);
|
||||
assertThat(attachmentRepository.findByRefTypeAndRefId("link", vo.getId())).isEmpty();
|
||||
|
||||
com.yunhai.cms.model.vo.AttachmentVo logo = attachmentService.upload(
|
||||
TestUsers.superAdmin(), siteId, null, "link", pngFile());
|
||||
LinkSaveRequest withLogo = req("先有Logo", "https://www.example.com");
|
||||
withLogo.setId(vo.getId());
|
||||
withLogo.setLogoUrl(logo.getUrl());
|
||||
linkService.save(TestUsers.superAdmin(), withLogo);
|
||||
assertThat(attachmentRepository.findByRefTypeAndRefId("link", vo.getId()))
|
||||
.extracting(com.yunhai.cms.entity.CmsAttachment::getId)
|
||||
.containsExactly(logo.getId());
|
||||
|
||||
// logo 清空(改回纯文字)→ 引用解除
|
||||
LinkSaveRequest clear = req("再去Logo", "https://www.example.com");
|
||||
clear.setId(vo.getId());
|
||||
clear.setLogoUrl("");
|
||||
linkService.save(TestUsers.superAdmin(), clear);
|
||||
assertThat(attachmentRepository.findByRefTypeAndRefId("link", vo.getId())).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user