fix: hide hidden skills from regular viewers

This commit is contained in:
yun-zhi-ztl 2026-03-17 14:29:07 +08:00 • committed by Xudong Sun
parent e52853c49c
commit a569707710
3 changed files with 61 additions and 0 deletions

View file

@ -7,6 +7,9 @@ import java.util.Map;
public class VisibilityChecker {
public boolean canAccess(Skill skill, String currentUserId, Map<Long, NamespaceRole> userNamespaceRoles) {
if (skill.isHidden()) {
return isOwner(skill, currentUserId) || isAdminOrAbove(userNamespaceRoles.get(skill.getNamespaceId()));
}
if (skill.getLatestVersionId() == null) {
return isOwner(skill, currentUserId);
}

View file

@ -15,6 +15,7 @@ class VisibilityCheckerTest {
private Skill namespaceOnlySkill;
private Skill privateSkill;
private Skill unpublishedPublicSkill;
private Skill hiddenPublicSkill;
private static final Long NAMESPACE_ID = 1L;
private static final String OWNER_ID = "user-100";
@ -33,6 +34,9 @@ class VisibilityCheckerTest {
privateSkill = new Skill(NAMESPACE_ID, "private-skill", OWNER_ID, SkillVisibility.PRIVATE);
privateSkill.setLatestVersionId(12L);
unpublishedPublicSkill = new Skill(NAMESPACE_ID, "draft-public-skill", OWNER_ID, SkillVisibility.PUBLIC);
hiddenPublicSkill = new Skill(NAMESPACE_ID, "hidden-public-skill", OWNER_ID, SkillVisibility.PUBLIC);
hiddenPublicSkill.setLatestVersionId(13L);
hiddenPublicSkill.setHidden(true);
}
@Test
@ -129,4 +133,29 @@ class VisibilityCheckerTest {
boolean canAccess = checker.canAccess(unpublishedPublicSkill, OWNER_ID, Map.of());
assertTrue(canAccess);
}
@Test
void testHiddenSkillNotAccessibleByAnonymous() {
boolean canAccess = checker.canAccess(hiddenPublicSkill, null, Map.of());
assertFalse(canAccess);
}
@Test
void testHiddenSkillNotAccessibleByOtherUser() {
boolean canAccess = checker.canAccess(hiddenPublicSkill, OTHER_USER_ID, Map.of());
assertFalse(canAccess);
}
@Test
void testHiddenSkillAccessibleByOwner() {
boolean canAccess = checker.canAccess(hiddenPublicSkill, OWNER_ID, Map.of());
assertTrue(canAccess);
}
@Test
void testHiddenSkillAccessibleByNamespaceAdmin() {
Map<Long, NamespaceRole> roles = Map.of(NAMESPACE_ID, NamespaceRole.ADMIN);
boolean canAccess = checker.canAccess(hiddenPublicSkill, ADMIN_USER_ID, roles);
assertTrue(canAccess);
}
}

View file

@ -257,6 +257,35 @@ class SkillQueryServiceTest {
assertEquals("own-skill", result.getContent().get(0).getSlug());
}
@Test
void testListSkillsByNamespace_ShouldHideHiddenSkillsFromRegularUsers() throws Exception {
String namespaceSlug = "test-ns";
String userId = "user-100";
Map<Long, NamespaceRole> userNsRoles = Map.of();
Pageable pageable = PageRequest.of(0, 10);
Namespace namespace = new Namespace(namespaceSlug, "Test NS", "user-1");
setId(namespace, 1L);
Skill visibleSkill = new Skill(1L, "visible-skill", "user-200", SkillVisibility.PUBLIC);
setId(visibleSkill, 1L);
visibleSkill.setLatestVersionId(11L);
Skill hiddenSkill = new Skill(1L, "hidden-skill", "user-300", SkillVisibility.PUBLIC);
setId(hiddenSkill, 2L);
hiddenSkill.setLatestVersionId(12L);
hiddenSkill.setHidden(true);
when(namespaceRepository.findBySlug(namespaceSlug)).thenReturn(Optional.of(namespace));
when(skillRepository.findByNamespaceIdAndStatus(1L, SkillStatus.ACTIVE))
.thenReturn(List.of(visibleSkill, hiddenSkill));
when(visibilityChecker.canAccess(visibleSkill, userId, userNsRoles)).thenReturn(true);
when(visibilityChecker.canAccess(hiddenSkill, userId, userNsRoles)).thenReturn(false);
Page<Skill> result = service.listSkillsByNamespace(namespaceSlug, userId, userNsRoles, pageable);
assertEquals(1, result.getTotalElements());
assertEquals("visible-skill", result.getContent().get(0).getSlug());
}
@Test
void testListFiles() throws Exception {
// Arrange