mirror of
https://github.com/iflytek/skillhub.git
synced 2026-09-11 22:51:04 +00:00
fix(suite): align super admin member selection
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
parent
a4b35b236a
commit
2e0cd691aa
4 changed files with 53 additions and 14 deletions
|
|
@ -344,7 +344,7 @@ public class SkillSuiteAppService {
|
|||
.orElseThrow(() -> new DomainBadRequestException(
|
||||
"error.namespace.slug.notFound", request.namespace()));
|
||||
SkillSuiteDraftService.CreatedDraft created = draftService.create(
|
||||
toCommand(namespace.getId(), request, userId, namespaceRoles),
|
||||
toCommand(namespace.getId(), request, userId, namespaceRoles, platformRoles),
|
||||
context(userId, namespaceRoles, platformRoles, httpRequest));
|
||||
return toResponse(namespace, created, userId, namespaceRoles, platformRoles);
|
||||
}
|
||||
|
|
@ -361,7 +361,7 @@ public class SkillSuiteAppService {
|
|||
.orElseThrow(() -> new DomainBadRequestException(
|
||||
"error.namespace.slug.notFound", request.namespace()));
|
||||
SkillSuiteDraftService.CreatedDraft created = draftService.createVersion(
|
||||
suiteId, toCommand(namespace.getId(), request, userId, namespaceRoles),
|
||||
suiteId, toCommand(namespace.getId(), request, userId, namespaceRoles, platformRoles),
|
||||
context(userId, namespaceRoles, platformRoles, httpRequest));
|
||||
return toResponse(namespace, created, userId, namespaceRoles, platformRoles);
|
||||
}
|
||||
|
|
@ -379,7 +379,7 @@ public class SkillSuiteAppService {
|
|||
.orElseThrow(() -> new DomainBadRequestException(
|
||||
"error.namespace.slug.notFound", request.namespace()));
|
||||
SkillSuiteDraftService.CreatedDraft updated = draftService.updateDraft(
|
||||
suiteId, versionId, toCommand(namespace.getId(), request, userId, namespaceRoles),
|
||||
suiteId, versionId, toCommand(namespace.getId(), request, userId, namespaceRoles, platformRoles),
|
||||
context(userId, namespaceRoles, platformRoles, httpRequest));
|
||||
return toResponse(namespace, updated, userId, namespaceRoles, platformRoles);
|
||||
}
|
||||
|
|
@ -510,10 +510,11 @@ public class SkillSuiteAppService {
|
|||
private SkillSuiteMemberSelection resolve(
|
||||
SkillSuiteMemberRequest member,
|
||||
String userId,
|
||||
Map<Long, NamespaceRole> namespaceRoles
|
||||
Map<Long, NamespaceRole> namespaceRoles,
|
||||
Set<String> platformRoles
|
||||
) {
|
||||
SkillQueryService.ResolvedVersionDTO resolved = skillQueryService.resolveVersionById(
|
||||
member.skillVersionId(), userId, namespaceRoles);
|
||||
member.skillVersionId(), userId, namespaceRoles, platformRoles);
|
||||
if (!Objects.equals(resolved.namespace(), member.namespace())
|
||||
|| !Objects.equals(resolved.slug(), member.slug())
|
||||
|| !Objects.equals(resolved.version(), member.version())) {
|
||||
|
|
@ -528,10 +529,11 @@ public class SkillSuiteAppService {
|
|||
Long namespaceId,
|
||||
SkillSuiteCreateRequest request,
|
||||
String userId,
|
||||
Map<Long, NamespaceRole> namespaceRoles
|
||||
Map<Long, NamespaceRole> namespaceRoles,
|
||||
Set<String> platformRoles
|
||||
) {
|
||||
List<SkillSuiteMemberSelection> selections = request.members().stream()
|
||||
.map(member -> resolve(member, userId, namespaceRoles))
|
||||
.map(member -> resolve(member, userId, namespaceRoles, platformRoles))
|
||||
.toList();
|
||||
Long entryVersionId = resolveEntryVersionId(request.entrySkill(), selections);
|
||||
return new CreateSkillSuiteDraftCommand(
|
||||
|
|
|
|||
|
|
@ -273,18 +273,19 @@ class SkillSuiteAppServiceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
void create_rejectsWhenExactVersionIdDoesNotMatchTheSubmittedCoordinate() {
|
||||
void create_rejectsCoordinateMismatchAfterResolvingWithPlatformRoles() {
|
||||
SkillSuiteMemberRequest member = new SkillSuiteMemberRequest(
|
||||
101L, "global", "selected", "1.0.0");
|
||||
SkillSuiteCreateRequest createRequest = new SkillSuiteCreateRequest(
|
||||
"global", "starter", "Starter", null, null, "1.0.0",
|
||||
SkillVisibility.PRIVATE, null, member, List.of(member));
|
||||
given(namespaceRepository.findBySlug("global")).willReturn(java.util.Optional.of(namespace));
|
||||
given(skillQueryService.resolveVersionById(101L, "user-1", Map.of()))
|
||||
given(skillQueryService.resolveVersionById(
|
||||
101L, "user-1", Map.of(), Set.of("SUPER_ADMIN")))
|
||||
.willReturn(resolved(99L, 101L, "different", "1.0.0", "sha256:different"));
|
||||
|
||||
assertThatThrownBy(() -> service.create(
|
||||
createRequest, "user-1", Map.of(), Set.of(), request))
|
||||
createRequest, "user-1", Map.of(), Set.of("SUPER_ADMIN"), request))
|
||||
.isInstanceOfSatisfying(DomainBadRequestException.class, exception ->
|
||||
assertThat(exception.messageCode())
|
||||
.isEqualTo("error.suite.members.selectionMismatch"));
|
||||
|
|
|
|||
|
|
@ -626,7 +626,8 @@ public class SkillQueryService {
|
|||
public ResolvedVersionDTO resolveVersionById(
|
||||
Long versionId,
|
||||
String currentUserId,
|
||||
Map<Long, NamespaceRole> userNsRoles
|
||||
Map<Long, NamespaceRole> userNsRoles,
|
||||
Set<String> platformRoles
|
||||
) {
|
||||
SkillVersion version = skillVersionRepository.findById(versionId)
|
||||
.orElseThrow(() -> new DomainBadRequestException("error.skill.version.notFound", versionId));
|
||||
|
|
@ -635,7 +636,7 @@ public class SkillQueryService {
|
|||
Namespace namespace = namespaceRepository.findById(skill.getNamespaceId())
|
||||
.orElseThrow(() -> new DomainBadRequestException(
|
||||
"error.namespace.id.notFound", skill.getNamespaceId()));
|
||||
assertPublishedAccessible(namespace, skill, currentUserId, userNsRoles);
|
||||
assertPublishedAccessible(namespace, skill, currentUserId, userNsRoles, platformRoles);
|
||||
assertInstallableVersion(version, version.getVersion());
|
||||
String fingerprint = computeFingerprint(version);
|
||||
return new ResolvedVersionDTO(
|
||||
|
|
@ -881,6 +882,15 @@ public class SkillQueryService {
|
|||
Skill skill,
|
||||
String currentUserId,
|
||||
Map<Long, NamespaceRole> userNsRoles) {
|
||||
assertPublishedAccessible(namespace, skill, currentUserId, userNsRoles, Set.of());
|
||||
}
|
||||
|
||||
private void assertPublishedAccessible(
|
||||
Namespace namespace,
|
||||
Skill skill,
|
||||
String currentUserId,
|
||||
Map<Long, NamespaceRole> userNsRoles,
|
||||
Set<String> platformRoles) {
|
||||
if (namespace.getStatus() == NamespaceStatus.ARCHIVED && !isNamespaceMember(skill.getNamespaceId(), currentUserId, userNsRoles)) {
|
||||
throw new DomainForbiddenException("error.namespace.archived", namespace.getSlug());
|
||||
}
|
||||
|
|
@ -890,7 +900,7 @@ public class SkillQueryService {
|
|||
if (skill.isHidden() && !canManageRestrictedSkill(skill, currentUserId, userNsRoles)) {
|
||||
throw new DomainForbiddenException("error.skill.access.denied", skill.getSlug());
|
||||
}
|
||||
if (!visibilityChecker.canAccess(skill, currentUserId, userNsRoles)) {
|
||||
if (!visibilityChecker.canAccess(skill, currentUserId, userNsRoles, platformRoles)) {
|
||||
throw new DomainForbiddenException("error.skill.access.denied", skill.getSlug());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -765,7 +765,7 @@ class SkillQueryServiceTest {
|
|||
when(skillFileRepository.findByVersionId(220L)).thenReturn(List.of(file));
|
||||
|
||||
SkillQueryService.ResolvedVersionDTO result = service.resolveVersionById(
|
||||
220L, "current-owner", Map.of(1L, NamespaceRole.MEMBER));
|
||||
220L, "current-owner", Map.of(1L, NamespaceRole.MEMBER), Set.of());
|
||||
|
||||
assertEquals(22L, result.skillId());
|
||||
assertEquals(220L, result.versionId());
|
||||
|
|
@ -774,6 +774,32 @@ class SkillQueryServiceTest {
|
|||
verify(skillRepository, never()).findByNamespaceIdAndSlug(anyLong(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResolveVersionById_ShouldAllowSuperAdminToSelectPrivatePublishedSkill() throws Exception {
|
||||
Namespace namespace = new Namespace("team", "Team", "namespace-owner");
|
||||
setId(namespace, 1L);
|
||||
Skill selected = new Skill(1L, "private-member", "skill-owner", SkillVisibility.PRIVATE);
|
||||
setId(selected, 22L);
|
||||
selected.setStatus(SkillStatus.ACTIVE);
|
||||
selected.setLatestVersionId(220L);
|
||||
SkillVersion selectedVersion = new SkillVersion(22L, "1.0.0", "skill-owner");
|
||||
setId(selectedVersion, 220L);
|
||||
selectedVersion.setStatus(SkillVersionStatus.PUBLISHED);
|
||||
selectedVersion.setDownloadReady(true);
|
||||
SkillFile file = new SkillFile(220L, "SKILL.md", 10L, "text/markdown", "hash", "key");
|
||||
|
||||
when(skillVersionRepository.findById(220L)).thenReturn(Optional.of(selectedVersion));
|
||||
when(skillRepository.findById(22L)).thenReturn(Optional.of(selected));
|
||||
when(namespaceRepository.findById(1L)).thenReturn(Optional.of(namespace));
|
||||
when(skillFileRepository.findByVersionId(220L)).thenReturn(List.of(file));
|
||||
|
||||
SkillQueryService.ResolvedVersionDTO result = service.resolveVersionById(
|
||||
220L, "super-admin", Map.of(), Set.of("SUPER_ADMIN"));
|
||||
|
||||
assertEquals(220L, result.versionId());
|
||||
assertEquals("private-member", result.slug());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResolveVersion_ShouldRejectDownloadUnavailableLatestVersion() throws Exception {
|
||||
String namespaceSlug = "global";
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue