feat(review): add ReviewPermissionChecker with tests

- canReview: self-review blocked, GLOBAL requires SKILL_ADMIN/SUPER_ADMIN,
  TEAM requires namespace ADMIN/OWNER
- canReviewPromotion: self-review blocked, requires SKILL_ADMIN/SUPER_ADMIN
- NamespaceType passed as parameter to avoid internal repository lookup
- 12 unit tests covering all permission scenarios
This commit is contained in:
vsxd 2026-03-12 15:24:51 +08:00
parent 3ebdc2691d
commit 644b3efd44
2 changed files with 172 additions and 0 deletions

View file

@ -0,0 +1,60 @@
package com.iflytek.skillhub.domain.review;
import com.iflytek.skillhub.domain.namespace.NamespaceRole;
import com.iflytek.skillhub.domain.namespace.NamespaceType;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Set;
@Component
public class ReviewPermissionChecker {
/**
* Check if a user can review a ReviewTask.
*
* @param task the review task
* @param userId the reviewer's user ID
* @param namespaceType the type of the namespace
* @param userNamespaceRoles user's roles keyed by namespace ID
* @param platformRoles user's platform-level roles
* @return true if the user is allowed to review
*/
public boolean canReview(ReviewTask task,
Long userId,
NamespaceType namespaceType,
Map<Long, NamespaceRole> userNamespaceRoles,
Set<String> platformRoles) {
// Cannot review own submission
if (task.getSubmittedBy().equals(userId)) {
return false;
}
// Global namespace: only SKILL_ADMIN or SUPER_ADMIN
if (namespaceType == NamespaceType.GLOBAL) {
return platformRoles.contains("SKILL_ADMIN")
|| platformRoles.contains("SUPER_ADMIN");
}
// Team namespace: namespace ADMIN or OWNER
NamespaceRole role = userNamespaceRoles.get(
task.getNamespaceId());
return role == NamespaceRole.ADMIN
|| role == NamespaceRole.OWNER;
}
/**
* Check if a user can review a PromotionRequest.
* Only SKILL_ADMIN or SUPER_ADMIN, and not own.
*/
public boolean canReviewPromotion(
PromotionRequest request,
Long userId,
Set<String> platformRoles) {
if (request.getSubmittedBy().equals(userId)) {
return false;
}
return platformRoles.contains("SKILL_ADMIN")
|| platformRoles.contains("SUPER_ADMIN");
}
}

View file

@ -0,0 +1,112 @@
package com.iflytek.skillhub.domain.review;
import com.iflytek.skillhub.domain.namespace.NamespaceRole;
import com.iflytek.skillhub.domain.namespace.NamespaceType;
import org.junit.jupiter.api.Test;
import java.util.Map;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
class ReviewPermissionCheckerTest {
private final ReviewPermissionChecker checker = new ReviewPermissionChecker();
// --- canReview tests ---
@Test
void cannotReviewOwnSubmission() {
Long userId = 1L;
ReviewTask task = new ReviewTask(1L, 10L, userId);
assertFalse(checker.canReview(task, userId,
NamespaceType.TEAM, Map.of(), Set.of()));
}
@Test
void teamAdminCanReviewTeamSkill() {
ReviewTask task = new ReviewTask(1L, 10L, 2L);
assertTrue(checker.canReview(task, 1L,
NamespaceType.TEAM,
Map.of(10L, NamespaceRole.ADMIN), Set.of()));
}
@Test
void teamOwnerCanReviewTeamSkill() {
ReviewTask task = new ReviewTask(1L, 10L, 2L);
assertTrue(checker.canReview(task, 1L,
NamespaceType.TEAM,
Map.of(10L, NamespaceRole.OWNER), Set.of()));
}
@Test
void teamMemberCannotReviewTeamSkill() {
ReviewTask task = new ReviewTask(1L, 10L, 2L);
assertFalse(checker.canReview(task, 1L,
NamespaceType.TEAM,
Map.of(10L, NamespaceRole.MEMBER), Set.of()));
}
@Test
void skillAdminCanReviewGlobalSkill() {
ReviewTask task = new ReviewTask(1L, 1L, 2L);
assertTrue(checker.canReview(task, 1L,
NamespaceType.GLOBAL,
Map.of(), Set.of("SKILL_ADMIN")));
}
@Test
void superAdminCanReviewGlobalSkill() {
ReviewTask task = new ReviewTask(1L, 1L, 2L);
assertTrue(checker.canReview(task, 1L,
NamespaceType.GLOBAL,
Map.of(), Set.of("SUPER_ADMIN")));
}
@Test
void skillAdminCannotReviewTeamSkill() {
ReviewTask task = new ReviewTask(1L, 10L, 2L);
assertFalse(checker.canReview(task, 1L,
NamespaceType.TEAM,
Map.of(), Set.of("SKILL_ADMIN")));
}
@Test
void nonAdminCannotReviewGlobalSkill() {
ReviewTask task = new ReviewTask(1L, 1L, 2L);
assertFalse(checker.canReview(task, 1L,
NamespaceType.GLOBAL,
Map.of(), Set.of()));
}
// --- canReviewPromotion tests ---
@Test
void skillAdminCanReviewPromotion() {
PromotionRequest req = new PromotionRequest(1L, 1L, 1L, 2L);
assertTrue(checker.canReviewPromotion(req, 1L,
Set.of("SKILL_ADMIN")));
}
@Test
void superAdminCanReviewPromotion() {
PromotionRequest req = new PromotionRequest(1L, 1L, 1L, 2L);
assertTrue(checker.canReviewPromotion(req, 1L,
Set.of("SUPER_ADMIN")));
}
@Test
void regularUserCannotReviewPromotion() {
PromotionRequest req = new PromotionRequest(1L, 1L, 1L, 2L);
assertFalse(checker.canReviewPromotion(req, 1L,
Set.of()));
}
@Test
void cannotReviewOwnPromotion() {
Long userId = 2L;
PromotionRequest req = new PromotionRequest(1L, 1L, 1L, userId);
assertFalse(checker.canReviewPromotion(req, userId,
Set.of("SKILL_ADMIN")));
}
}