- 实体/双 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 全绿
92 lines
3.9 KiB
Java
92 lines
3.9 KiB
Java
package com.yunhai.cms.service.impl;
|
|
|
|
import com.yunhai.cms.entity.CmsLink;
|
|
import com.yunhai.cms.entity.CmsSite;
|
|
import com.yunhai.cms.event.SiteContentChangedEvent;
|
|
import com.yunhai.cms.model.dto.DeleteRequest;
|
|
import com.yunhai.cms.model.dto.LinkSaveRequest;
|
|
import com.yunhai.cms.model.vo.LinkVo;
|
|
import com.yunhai.cms.repository.CmsLinkRepository;
|
|
import com.yunhai.platform.apistd.BizException;
|
|
import com.yunhai.platform.utils.exception.ErrorCode;
|
|
import com.yunhai.platform.utils.model.BoaUser;
|
|
import lombok.RequiredArgsConstructor;
|
|
import org.springframework.context.ApplicationEventPublisher;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.util.StringUtils;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* 友情链接管理(方案 §9.1 友情链接管理)。
|
|
*/
|
|
@Service
|
|
@RequiredArgsConstructor
|
|
public class LinkService {
|
|
|
|
private final CmsLinkRepository linkRepository;
|
|
private final SiteService siteService;
|
|
private final ApplicationEventPublisher eventPublisher;
|
|
private final AttachmentService attachmentService;
|
|
|
|
public List<LinkVo> list(BoaUser user, Integer siteId) {
|
|
siteService.requireManageable(user, siteId);
|
|
List<CmsLink> links = linkRepository.findBySiteIdOrderByGroupNameAscSortNoAscIdAsc(siteId);
|
|
List<LinkVo> result = new ArrayList<>();
|
|
for (CmsLink l : links) {
|
|
result.add(LinkVo.of(l));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@Transactional
|
|
public LinkVo save(BoaUser user, LinkSaveRequest req) {
|
|
CmsSite site = siteService.requireManageable(user, req.getSiteId());
|
|
if (!StringUtils.hasText(req.getLinkUrl())
|
|
|| !(req.getLinkUrl().startsWith("http://") || req.getLinkUrl().startsWith("https://")
|
|
|| req.getLinkUrl().startsWith("/"))) {
|
|
throw new BizException(ErrorCode.PARAM_ERROR, "链接地址必须以 http(s):// 或 / 开头");
|
|
}
|
|
CmsLink link;
|
|
if (req.getId() == null) {
|
|
link = new CmsLink();
|
|
link.setSiteId(site.getId());
|
|
} else {
|
|
link = linkRepository.findById(req.getId())
|
|
.orElseThrow(() -> new BizException(ErrorCode.PARAM_ERROR, "友链不存在"));
|
|
if (!link.getSiteId().equals(site.getId())) {
|
|
throw new BizException(ErrorCode.FORBIDDEN, "无权修改该友链");
|
|
}
|
|
}
|
|
link.setGroupName(StringUtils.hasText(req.getGroupName()) ? req.getGroupName() : "default");
|
|
link.setName(req.getName());
|
|
link.setLogoUrl(req.getLogoUrl());
|
|
link.setLinkUrl(req.getLinkUrl());
|
|
link.setSortNo(req.getSortNo() == null ? 0 : req.getSortNo());
|
|
link.setStatus(req.getStatus() == null ? 1 : req.getStatus());
|
|
link = linkRepository.save(link);
|
|
// B2 附件引用:先解引用,logoUrl 非空才回写(编辑换图/清空 logo 旧图均回未使用);幂等
|
|
attachmentService.release("link", link.getId());
|
|
if (StringUtils.hasText(req.getLogoUrl())) {
|
|
attachmentService.markUsed(site.getId(), req.getLogoUrl(), "link", link.getId());
|
|
}
|
|
eventPublisher.publishEvent(new SiteContentChangedEvent(site.getId(), "link"));
|
|
return LinkVo.of(link);
|
|
}
|
|
|
|
@Transactional
|
|
public void delete(BoaUser user, DeleteRequest req) {
|
|
CmsSite site = siteService.requireManageable(user, req.getSiteId());
|
|
CmsLink link = linkRepository.findById(req.getId())
|
|
.orElseThrow(() -> new BizException(ErrorCode.PARAM_ERROR, "友链不存在"));
|
|
if (!link.getSiteId().equals(site.getId())) {
|
|
throw new BizException(ErrorCode.FORBIDDEN, "无权删除该友链");
|
|
}
|
|
linkRepository.delete(link);
|
|
attachmentService.release("link", link.getId());
|
|
eventPublisher.publishEvent(new SiteContentChangedEvent(site.getId(), "link"));
|
|
}
|
|
}
|