mirror of
https://github.com/iflytek/skillhub.git
synced 2026-10-09 03:17:52 +00:00
feat(api): unify permission checks for hide/unhide/archive operations
Add unified permission model for skill lifecycle operations:
- Skill owners can hide/unhide/archive their own skills
- Namespace admins/owners can manage skills in their namespace
- Platform admins retain full access via admin endpoints
Changes:
- SkillGovernanceService: add permission checks to hideSkill/unhideSkill
- SkillLifecycleAppService: add hideSkill/unhideSkill methods
- GovernanceWorkflowAppService: add facade methods for hide/unhide
- SkillLifecycleController: add POST /{namespace}/{slug}/hide and /unhide endpoints
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
parent
c14b844c10
commit
1ba1c9018a
4 changed files with 113 additions and 17 deletions
|
|
@ -141,11 +141,11 @@ public class SkillLifecycleController extends BaseApiController {
|
|||
|
||||
@PostMapping("/{namespace}/{slug}/confirm-publish")
|
||||
public ApiResponse<SkillLifecycleMutationResponse> confirmPublish(@PathVariable String namespace,
|
||||
@PathVariable String slug,
|
||||
@Valid @RequestBody ConfirmPublishRequest request,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute(value = "userNsRoles", required = false) Map<Long, NamespaceRole> userNsRoles,
|
||||
HttpServletRequest httpRequest) {
|
||||
@PathVariable String slug,
|
||||
@Valid @RequestBody ConfirmPublishRequest request,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute(value = "userNsRoles", required = false) Map<Long, NamespaceRole> userNsRoles,
|
||||
HttpServletRequest httpRequest) {
|
||||
return ok("response.success.updated",
|
||||
governanceWorkflowAppService.confirmPublish(
|
||||
namespace,
|
||||
|
|
@ -155,4 +155,36 @@ public class SkillLifecycleController extends BaseApiController {
|
|||
userNsRoles,
|
||||
AuditRequestContext.from(httpRequest)));
|
||||
}
|
||||
|
||||
@PostMapping("/{namespace}/{slug}/hide")
|
||||
public ApiResponse<SkillLifecycleMutationResponse> hideSkill(@PathVariable String namespace,
|
||||
@PathVariable String slug,
|
||||
@RequestBody(required = false) AdminSkillActionRequest request,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute(value = "userNsRoles", required = false) Map<Long, NamespaceRole> userNsRoles,
|
||||
HttpServletRequest httpRequest) {
|
||||
return ok("response.success.updated",
|
||||
governanceWorkflowAppService.hideSkill(
|
||||
namespace,
|
||||
slug,
|
||||
request,
|
||||
userId,
|
||||
userNsRoles,
|
||||
AuditRequestContext.from(httpRequest)));
|
||||
}
|
||||
|
||||
@PostMapping("/{namespace}/{slug}/unhide")
|
||||
public ApiResponse<SkillLifecycleMutationResponse> unhideSkill(@PathVariable String namespace,
|
||||
@PathVariable String slug,
|
||||
@RequestAttribute("userId") String userId,
|
||||
@RequestAttribute(value = "userNsRoles", required = false) Map<Long, NamespaceRole> userNsRoles,
|
||||
HttpServletRequest httpRequest) {
|
||||
return ok("response.success.updated",
|
||||
governanceWorkflowAppService.unhideSkill(
|
||||
namespace,
|
||||
slug,
|
||||
userId,
|
||||
userNsRoles,
|
||||
AuditRequestContext.from(httpRequest)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -273,11 +273,11 @@ public class GovernanceWorkflowAppService {
|
|||
}
|
||||
|
||||
public SkillLifecycleMutationResponse confirmPublish(String namespace,
|
||||
String slug,
|
||||
String version,
|
||||
String userId,
|
||||
Map<Long, NamespaceRole> userNsRoles,
|
||||
AuditRequestContext auditContext) {
|
||||
String slug,
|
||||
String version,
|
||||
String userId,
|
||||
Map<Long, NamespaceRole> userNsRoles,
|
||||
AuditRequestContext auditContext) {
|
||||
return skillLifecycleAppService.confirmPublish(
|
||||
namespace,
|
||||
slug,
|
||||
|
|
@ -286,4 +286,21 @@ public class GovernanceWorkflowAppService {
|
|||
userNsRoles,
|
||||
auditContext);
|
||||
}
|
||||
|
||||
public SkillLifecycleMutationResponse hideSkill(String namespace,
|
||||
String slug,
|
||||
AdminSkillActionRequest request,
|
||||
String userId,
|
||||
Map<Long, NamespaceRole> userNsRoles,
|
||||
AuditRequestContext auditContext) {
|
||||
return skillLifecycleAppService.hideSkill(namespace, slug, request, userId, userNsRoles, auditContext);
|
||||
}
|
||||
|
||||
public SkillLifecycleMutationResponse unhideSkill(String namespace,
|
||||
String slug,
|
||||
String userId,
|
||||
Map<Long, NamespaceRole> userNsRoles,
|
||||
AuditRequestContext auditContext) {
|
||||
return skillLifecycleAppService.unhideSkill(namespace, slug, userId, userNsRoles, auditContext);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,11 +213,11 @@ public class SkillLifecycleAppService {
|
|||
|
||||
@Transactional
|
||||
public SkillLifecycleMutationResponse confirmPublish(String namespace,
|
||||
String slug,
|
||||
String version,
|
||||
String userId,
|
||||
Map<Long, NamespaceRole> userNamespaceRoles,
|
||||
AuditRequestContext auditContext) {
|
||||
String slug,
|
||||
String version,
|
||||
String userId,
|
||||
Map<Long, NamespaceRole> userNamespaceRoles,
|
||||
AuditRequestContext auditContext) {
|
||||
Skill skill = findSkill(namespace, slug, userId);
|
||||
SkillVersion skillVersion = findVersion(skill.getId(), version);
|
||||
skillReviewSubmitService.confirmPublish(
|
||||
|
|
@ -244,6 +244,42 @@ public class SkillLifecycleAppService {
|
|||
);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public SkillLifecycleMutationResponse hideSkill(String namespace,
|
||||
String slug,
|
||||
AdminSkillActionRequest request,
|
||||
String userId,
|
||||
Map<Long, NamespaceRole> userNamespaceRoles,
|
||||
AuditRequestContext auditContext) {
|
||||
Skill skill = findSkill(namespace, slug, userId);
|
||||
Skill hidden = skillGovernanceService.hideSkill(
|
||||
skill.getId(),
|
||||
userId,
|
||||
normalizeRoles(userNamespaceRoles),
|
||||
auditContext.clientIp(),
|
||||
auditContext.userAgent(),
|
||||
request != null ? request.reason() : null
|
||||
);
|
||||
return new SkillLifecycleMutationResponse(hidden.getId(), null, "HIDE", hidden.getStatus().name());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public SkillLifecycleMutationResponse unhideSkill(String namespace,
|
||||
String slug,
|
||||
String userId,
|
||||
Map<Long, NamespaceRole> userNamespaceRoles,
|
||||
AuditRequestContext auditContext) {
|
||||
Skill skill = findSkill(namespace, slug, userId);
|
||||
Skill unhidden = skillGovernanceService.unhideSkill(
|
||||
skill.getId(),
|
||||
userId,
|
||||
normalizeRoles(userNamespaceRoles),
|
||||
auditContext.clientIp(),
|
||||
auditContext.userAgent()
|
||||
);
|
||||
return new SkillLifecycleMutationResponse(unhidden.getId(), null, "UNHIDE", unhidden.getStatus().name());
|
||||
}
|
||||
|
||||
private Skill findSkill(String namespaceSlug, String skillSlug, String currentUserId) {
|
||||
String cleanNamespace = namespaceSlug.startsWith("@") ? namespaceSlug.substring(1) : namespaceSlug;
|
||||
Namespace namespace = namespaceRepository.findBySlug(cleanNamespace)
|
||||
|
|
|
|||
|
|
@ -69,9 +69,15 @@ public class SkillGovernanceService {
|
|||
}
|
||||
|
||||
@Transactional
|
||||
public Skill hideSkill(Long skillId, String actorUserId, String clientIp, String userAgent, String reason) {
|
||||
public Skill hideSkill(Long skillId,
|
||||
String actorUserId,
|
||||
Map<Long, NamespaceRole> userNamespaceRoles,
|
||||
String clientIp,
|
||||
String userAgent,
|
||||
String reason) {
|
||||
Skill skill = skillRepository.findById(skillId)
|
||||
.orElseThrow(() -> new DomainNotFoundException("error.skill.notFound", skillId));
|
||||
assertCanManageLifecycle(skill, actorUserId, userNamespaceRoles);
|
||||
skill.setHidden(true);
|
||||
skill.setHiddenAt(currentInstant());
|
||||
skill.setHiddenBy(actorUserId);
|
||||
|
|
@ -120,9 +126,14 @@ public class SkillGovernanceService {
|
|||
}
|
||||
|
||||
@Transactional
|
||||
public Skill unhideSkill(Long skillId, String actorUserId, String clientIp, String userAgent) {
|
||||
public Skill unhideSkill(Long skillId,
|
||||
String actorUserId,
|
||||
Map<Long, NamespaceRole> userNamespaceRoles,
|
||||
String clientIp,
|
||||
String userAgent) {
|
||||
Skill skill = skillRepository.findById(skillId)
|
||||
.orElseThrow(() -> new DomainNotFoundException("error.skill.notFound", skillId));
|
||||
assertCanManageLifecycle(skill, actorUserId, userNamespaceRoles);
|
||||
skill.setHidden(false);
|
||||
skill.setHiddenAt(null);
|
||||
skill.setHiddenBy(null);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue