init local code

This commit is contained in:
chenxing
2026-09-07 09:09:39 +08:00
commit 99cd26b3d2
259 changed files with 20554 additions and 0 deletions
@@ -0,0 +1,139 @@
package com.yunhai.cms.service.impl;
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.support.CmsIntegrationTestBase;
import com.yunhai.cms.support.TestUsers;
import com.yunhai.platform.apistd.BizException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* 友情链接管理集成测试(方案 §5.1 表6 / §9.2)。
*/
@DisplayName("LinkService - 友情链接管理")
@Transactional
class LinkServiceIT extends CmsIntegrationTestBase {
@Autowired
private LinkService linkService;
private Integer siteId;
@BeforeEach
void seed() {
siteId = persistSite("demo1", 1, "演示站点一").getId();
}
private LinkSaveRequest req(String name, String url) {
LinkSaveRequest r = new LinkSaveRequest();
r.setSiteId(siteId);
r.setName(name);
r.setLinkUrl(url);
return r;
}
@Test
@DisplayName("保存友链:http/https/站内相对路径均接受;分组与默认值生效")
void save_urlSchemesAndDefaults() {
assertThat(linkService.save(TestUsers.superAdmin(), req("教育部", "http://www.moe.gov.cn")).getId())
.isNotNull();
assertThat(linkService.save(TestUsers.superAdmin(), req("兄弟院校", "https://www.pku.edu.cn")).getId())
.isNotNull();
LinkVo relative = linkService.save(TestUsers.superAdmin(), req("站内页", "/cms/portal/demo1/"));
assertThat(relative.getGroupName()).isEqualTo("default"); // 分组缺省
assertThat(relative.getSortNo()).isZero();
assertThat(relative.getStatus()).isEqualTo(1);
}
@Test
@DisplayName("保存友链:javascript: 等非法协议与空地址被拒")
void save_invalidUrlRejected() {
assertThatThrownBy(() -> linkService.save(
TestUsers.superAdmin(), req("危险链", "javascript:alert(1)")))
.isInstanceOf(BizException.class)
.hasMessageContaining("http");
assertThatThrownBy(() -> linkService.save(TestUsers.superAdmin(), req("空链", "")))
.isInstanceOf(BizException.class)
.hasMessageContaining("http");
assertThatThrownBy(() -> linkService.save(
TestUsers.superAdmin(), req("数据协议", "data:text/html,<script>")))
.isInstanceOf(BizException.class)
.hasMessageContaining("http");
}
@Test
@DisplayName("列表按分组名+组内排序返回全量(含隐藏,供管理端)")
void list_orderedByGroupAndSort() {
LinkSaveRequest b = req("B链", "https://b.example.com");
b.setGroupName("上级部门");
b.setSortNo(2);
linkService.save(TestUsers.superAdmin(), b);
LinkSaveRequest a = req("A链", "https://a.example.com");
a.setGroupName("上级部门");
a.setSortNo(1);
linkService.save(TestUsers.superAdmin(), a);
LinkSaveRequest coop = req("合作单位链", "https://c.example.com");
coop.setGroupName("合作单位");
linkService.save(TestUsers.superAdmin(), coop);
LinkSaveRequest hidden = req("隐藏链", "https://h.example.com");
hidden.setStatus(0);
linkService.save(TestUsers.superAdmin(), hidden);
List<LinkVo> list = linkService.list(TestUsers.superAdmin(), siteId);
// 分组名升序走 MySQL utf8mb4_general_ci:ASCII "default" < 中文(上 U+4E0A < 合 U+5408)
assertThat(list).extracting(LinkVo::getName)
.containsExactly("隐藏链", "A链", "B链", "合作单位链");
}
@Test
@DisplayName("修改/删除他站友链抛 FORBIDDEN;删除本站成功")
void crossSiteAndDelete() {
LinkVo own = linkService.save(TestUsers.superAdmin(), req("待删链", "https://x.example.com"));
Integer otherSiteId = persistSite("demo2", 2, "演示站点二").getId();
LinkSaveRequest hijack = req("越权改链", "https://y.example.com");
hijack.setId(own.getId());
hijack.setSiteId(otherSiteId);
assertThatThrownBy(() -> linkService.save(TestUsers.superAdmin(), hijack))
.isInstanceOf(BizException.class)
.hasMessageContaining("无权");
DeleteRequest wrongSite = new DeleteRequest();
wrongSite.setSiteId(otherSiteId);
wrongSite.setId(own.getId());
assertThatThrownBy(() -> linkService.delete(TestUsers.superAdmin(), wrongSite))
.isInstanceOf(BizException.class)
.hasMessageContaining("无权");
DeleteRequest del = new DeleteRequest();
del.setSiteId(siteId);
del.setId(own.getId());
linkService.delete(TestUsers.superAdmin(), del);
assertThat(linkRepository.findById(own.getId())).isEmpty();
}
@Test
@DisplayName("删除不存在的友链报错(边界)")
void delete_missingRejected() {
DeleteRequest del = new DeleteRequest();
del.setSiteId(siteId);
del.setId(99999);
assertThatThrownBy(() -> linkService.delete(TestUsers.superAdmin(), del))
.isInstanceOf(BizException.class)
.hasMessageContaining("不存在");
}
}