完善角色权限与数据隔离

This commit is contained in:
yml2213
2026-07-26 14:00:50 +08:00
parent b483cbc26d
commit 16d9ab0e5e
38 changed files with 2847 additions and 292 deletions
+41 -14
View File
@@ -15,14 +15,18 @@ type KnowledgeHandler struct{}
func NewKnowledgeHandler() *KnowledgeHandler { return &KnowledgeHandler{} }
func requireKnowledgeManager(c *gin.Context) bool {
if middleware.HasAnyRole(c, "admin", "supervisor") {
func requireKnowledgePermission(c *gin.Context, code string) bool {
if middleware.HasPermission(c, code) {
return true
}
c.JSON(http.StatusForbidden, gin.H{"code": 403, "message": "仅主管或管理员可管理知识库"})
c.JSON(http.StatusForbidden, gin.H{"code": 403, "message": "无权执行该知识库操作"})
return false
}
func canDeleteKnowledge(c *gin.Context, createdBy uint) bool {
return middleware.GetRole(c) == "admin" || (createdBy != 0 && createdBy == middleware.GetUserID(c))
}
func hasKnowledgeCapacity(tenantID uint) (bool, error) {
var tenant model.Tenant
if err := model.DB.First(&tenant, tenantID).Error; err != nil {
@@ -139,7 +143,7 @@ var (
type catError string
func errCat(s string) catError { return catError(s) }
func errCat(s string) catError { return catError(s) }
func (e catError) Error() string { return string(e) }
func isCategoryNameTaken(tenantID uint, name string, parentID *uint, excludeID uint) bool {
@@ -158,7 +162,7 @@ func isCategoryNameTaken(tenantID uint, name string, parentID *uint, excludeID u
}
func (h *KnowledgeHandler) CreateCategory(c *gin.Context) {
if !requireKnowledgeManager(c) {
if !requireKnowledgePermission(c, "knowledge.create") {
return
}
var req CategoryReq
@@ -181,9 +185,10 @@ func (h *KnowledgeHandler) CreateCategory(c *gin.Context) {
return
}
category := model.Category{
TenantID: tenantID,
Name: name,
ParentID: req.ParentID,
TenantID: tenantID,
CreatedBy: middleware.GetUserID(c),
Name: name,
ParentID: req.ParentID,
}
if err := model.DB.Create(&category).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "创建失败"})
@@ -193,7 +198,7 @@ func (h *KnowledgeHandler) CreateCategory(c *gin.Context) {
}
func (h *KnowledgeHandler) UpdateCategory(c *gin.Context) {
if !requireKnowledgeManager(c) {
if !requireKnowledgePermission(c, "knowledge.edit") {
return
}
tenantID := middleware.GetTenantID(c)
@@ -248,7 +253,7 @@ func (h *KnowledgeHandler) UpdateCategory(c *gin.Context) {
}
func (h *KnowledgeHandler) DeleteCategory(c *gin.Context) {
if !requireKnowledgeManager(c) {
if !requireKnowledgePermission(c, "knowledge.delete") {
return
}
tenantID := middleware.GetTenantID(c)
@@ -258,6 +263,10 @@ func (h *KnowledgeHandler) DeleteCategory(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{"code": 404, "message": "分类不存在"})
return
}
if !canDeleteKnowledge(c, category.CreatedBy) {
c.JSON(http.StatusForbidden, gin.H{"code": 403, "message": "主管仅可删除自己创建的分类"})
return
}
var childCnt int64
model.DB.Model(&model.Category{}).Where("parent_id = ? AND tenant_id = ?", category.ID, tenantID).Count(&childCnt)
if childCnt > 0 {
@@ -364,7 +373,7 @@ func (h *KnowledgeHandler) ListEntries(c *gin.Context) {
}
func (h *KnowledgeHandler) CreateEntry(c *gin.Context) {
if !requireKnowledgeManager(c) {
if !requireKnowledgePermission(c, "knowledge.create") {
return
}
var entry model.KnowledgeEntry
@@ -373,6 +382,11 @@ func (h *KnowledgeHandler) CreateEntry(c *gin.Context) {
return
}
entry.TenantID = middleware.GetTenantID(c)
entry.CreatedBy = middleware.GetUserID(c)
if entry.Status == "published" && !middleware.HasPermission(c, "knowledge.publish") {
c.JSON(http.StatusForbidden, gin.H{"code": 403, "message": "无权直接发布知识条目"})
return
}
available, err := hasKnowledgeCapacity(entry.TenantID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "校验知识库容量失败"})
@@ -397,7 +411,7 @@ func (h *KnowledgeHandler) CreateEntry(c *gin.Context) {
}
func (h *KnowledgeHandler) UpdateEntry(c *gin.Context) {
if !requireKnowledgeManager(c) {
if !requireKnowledgePermission(c, "knowledge.edit") {
return
}
tenantID := middleware.GetTenantID(c)
@@ -432,6 +446,10 @@ func (h *KnowledgeHandler) UpdateEntry(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "没有可更新字段"})
return
}
if status, exists := updates["status"]; exists && status != entry.Status && !middleware.HasPermission(c, "knowledge.publish") {
c.JSON(http.StatusForbidden, gin.H{"code": 403, "message": "无权发布或下架知识条目"})
return
}
if err := model.DB.Model(&entry).Updates(updates).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "更新失败"})
@@ -442,13 +460,22 @@ func (h *KnowledgeHandler) UpdateEntry(c *gin.Context) {
}
func (h *KnowledgeHandler) DeleteEntry(c *gin.Context) {
if !requireKnowledgeManager(c) {
if !requireKnowledgePermission(c, "knowledge.delete") {
return
}
tenantID := middleware.GetTenantID(c)
id := c.Param("id")
result := model.DB.Where("id = ? AND tenant_id = ?", id, tenantID).Delete(&model.KnowledgeEntry{})
var entry model.KnowledgeEntry
if err := model.DB.Where("id = ? AND tenant_id = ?", id, tenantID).First(&entry).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"code": 404, "message": "条目不存在"})
return
}
if !canDeleteKnowledge(c, entry.CreatedBy) {
c.JSON(http.StatusForbidden, gin.H{"code": 403, "message": "主管仅可删除自己创建的知识条目"})
return
}
result := model.DB.Delete(&entry)
if result.RowsAffected == 0 {
c.JSON(http.StatusNotFound, gin.H{"code": 404, "message": "条目不存在"})
return