fix(server): allow members to create and manage their own skills (#1017)

Remove admin/owner-only restriction from skill creation and import routes.
Add canManageSkill helper that lets skill creators manage their own skills,
matching the existing canManageAgent pattern for agents.
This commit is contained in:
Bohan Jiang
2026-04-14 23:48:57 +08:00
committed by GitHub
parent a3c6f07668
commit b4b69f89f6
2 changed files with 23 additions and 6 deletions

View File

@@ -278,8 +278,8 @@ func NewRouter(pool *pgxpool.Pool, hub *realtime.Hub, bus *events.Bus) chi.Route
// Skills
r.Route("/api/skills", func(r chi.Router) {
r.Get("/", h.ListSkills)
r.With(middleware.RequireWorkspaceRole(queries, "owner", "admin")).Post("/", h.CreateSkill)
r.With(middleware.RequireWorkspaceRole(queries, "owner", "admin")).Post("/import", h.ImportSkill)
r.Post("/", h.CreateSkill)
r.Post("/import", h.ImportSkill)
r.Route("/{id}", func(r chi.Router) {
r.Get("/", h.GetSkill)
r.Put("/", h.UpdateSkill)

View File

@@ -268,13 +268,30 @@ func (h *Handler) CreateSkill(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusCreated, resp)
}
// canManageSkill checks whether the current user can update or delete a skill.
// The skill creator or workspace owner/admin can manage any skill.
func (h *Handler) canManageSkill(w http.ResponseWriter, r *http.Request, skill db.Skill) bool {
wsID := uuidToString(skill.WorkspaceID)
member, ok := h.requireWorkspaceRole(w, r, wsID, "skill not found", "owner", "admin", "member")
if !ok {
return false
}
isAdmin := roleAllowed(member.Role, "owner", "admin")
isSkillCreator := skill.CreatedBy.Valid && uuidToString(skill.CreatedBy) == requestUserID(r)
if !isAdmin && !isSkillCreator {
writeError(w, http.StatusForbidden, "only the skill creator can manage this skill")
return false
}
return true
}
func (h *Handler) UpdateSkill(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
skill, ok := h.loadSkillForUser(w, r, id)
if !ok {
return
}
if _, ok := h.requireWorkspaceRole(w, r, uuidToString(skill.WorkspaceID), "skill not found", "owner", "admin"); !ok {
if !h.canManageSkill(w, r, skill) {
return
}
@@ -376,7 +393,7 @@ func (h *Handler) DeleteSkill(w http.ResponseWriter, r *http.Request) {
if !ok {
return
}
if _, ok := h.requireWorkspaceRole(w, r, uuidToString(skill.WorkspaceID), "skill not found", "owner", "admin"); !ok {
if !h.canManageSkill(w, r, skill) {
return
}
@@ -913,7 +930,7 @@ func (h *Handler) UpsertSkillFile(w http.ResponseWriter, r *http.Request) {
if !ok {
return
}
if _, ok := h.requireWorkspaceRole(w, r, uuidToString(skill.WorkspaceID), "skill not found", "owner", "admin"); !ok {
if !h.canManageSkill(w, r, skill) {
return
}
@@ -947,7 +964,7 @@ func (h *Handler) DeleteSkillFile(w http.ResponseWriter, r *http.Request) {
if !ok {
return
}
if _, ok := h.requireWorkspaceRole(w, r, uuidToString(skill.WorkspaceID), "skill not found", "owner", "admin"); !ok {
if !h.canManageSkill(w, r, skill) {
return
}