@@ -68,12 +68,11 @@ public class AttachmentService {
|
||||
|
||||
/**
|
||||
* 上传 scene 白名单(B2 附件引用模型):banner=轮播 / link=友链 / site=站点配置 /
|
||||
* category=单页栏目贴图 / svc_item=事项指南附件(列表可见) / svc_item_asset=事项封面与正文内嵌资产。
|
||||
* 事项侧拆两个场景的原因:指南附件查询(refType=svc_item, refId=itemId)必须只返回"用户显式上传的附件",
|
||||
* 封面与正文图片若同场景会被混进指南页附件列表。
|
||||
* category=单页栏目贴图。svc_item/svc_item_asset 两个事项场景已随事项库迁出办事大厅
|
||||
* (V2.0,见 docs/19 §九),CMS 侧下线。
|
||||
*/
|
||||
private static final List<String> ALLOWED_SCENES =
|
||||
Arrays.asList("banner", "link", "site", "category", "svc_item", "svc_item_asset");
|
||||
Arrays.asList("banner", "link", "site", "category");
|
||||
|
||||
private final CmsAttachmentRepository attachmentRepository;
|
||||
private final SiteService siteService;
|
||||
@@ -85,13 +84,13 @@ public class AttachmentService {
|
||||
@Value("${FILE_WEB_PATH:/cms/upload/}")
|
||||
private String fileWebPath;
|
||||
|
||||
/** 上传(编辑器图片/附件/轮播图/Logo 复用);articleId 可空;scene 可空(banner/link/site/category/svc_item/svc_item_asset,B2 初步标记) */
|
||||
/** 上传(编辑器图片/附件/轮播图/Logo 复用);articleId 可空;scene 可空(banner/link/site/category) */
|
||||
@Transactional
|
||||
public AttachmentVo upload(BoaUser user, Integer siteId, Integer articleId, String scene, MultipartFile file) {
|
||||
CmsSite site = siteService.requireManageable(user, siteId);
|
||||
if (StringUtils.hasText(scene) && !ALLOWED_SCENES.contains(scene)) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR,
|
||||
"scene 非法:" + scene + "(仅 banner/link/site/category/svc_item/svc_item_asset)");
|
||||
"scene 非法:" + scene + "(仅 banner/link/site/category)");
|
||||
}
|
||||
if (file == null || file.isEmpty()) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "上传文件不能为空");
|
||||
|
||||
@@ -37,6 +37,9 @@ public class CategoryService {
|
||||
private static final java.util.Set<String> HOME_STYLE_VALUES =
|
||||
new java.util.HashSet<>(java.util.Arrays.asList("news_grid", "media_focus"));
|
||||
|
||||
/** 祖先链上溯上限(防脏数据自环导致死循环;正常栏目树远低于此深度) */
|
||||
private static final int MAX_ANCESTOR_WALK = 64;
|
||||
|
||||
private final CmsCategoryRepository categoryRepository;
|
||||
private final CmsArticleRepository articleRepository;
|
||||
private final com.yunhai.cms.repository.CmsBannerRepository bannerRepository;
|
||||
@@ -119,9 +122,29 @@ public class CategoryService {
|
||||
if (!parent.getSiteId().equals(req.getSiteId())) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "父栏目不属于该站点");
|
||||
}
|
||||
if (category.getId() != null && parent.getParentId() != null
|
||||
&& parent.getParentId().equals(category.getId())) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "不支持把子栏目设为父栏目(成环)");
|
||||
requireNoCycle(category, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 防环:从目标父栏目沿<b>祖先链</b>上溯,遇到"正在保存的栏目自身"即为环。
|
||||
*
|
||||
* <p>原实现只挡一级父子互换(parent.parentId == 自己),三级及以上的环写得进去;
|
||||
* 环会让整枝栏目在门户导航与栏目树上消失,故补成任意层级(前端下拉同步放开置灰,
|
||||
* 改为保存前同口径校验 + 明确提示,前后端口径一致)。
|
||||
*/
|
||||
private void requireNoCycle(CmsCategory category, CmsCategory parent) {
|
||||
if (category.getId() == null) {
|
||||
return;
|
||||
}
|
||||
int guard = 0;
|
||||
CmsCategory cursor = parent;
|
||||
while (cursor != null && guard++ <= MAX_ANCESTOR_WALK) {
|
||||
if (category.getId().equals(cursor.getId())) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR,
|
||||
"不支持把栏目挂到自身或自己的子栏目下(会成环)");
|
||||
}
|
||||
Integer next = cursor.getParentId();
|
||||
cursor = (next == null || next == 0) ? null : categoryRepository.findById(next).orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user