feat(plugins): 插件管理 - 区分系统与官方插件权限 (#329)
This commit is contained in:
@@ -38,7 +38,7 @@ func RegisterComfyBridgeRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
if err := svc.RequireWorkflowPluginForInterface("comfyui-bridge-image"); err != nil {
|
||||
if err := svc.RequireWorkflowPluginForUser(user.ID, "comfyui-bridge-image"); err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
@@ -61,7 +61,7 @@ func RegisterComfyBridgeRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
if err := svc.RequireWorkflowPluginForInterface("comfyui-bridge-image"); err != nil {
|
||||
if err := svc.RequireWorkflowPluginForUser(user.ID, "comfyui-bridge-image"); err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
@@ -78,10 +78,6 @@ func RegisterComfyBridgeRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
if err := svc.RequireWorkflowPluginForInterface("comfyui-bridge-image"); err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
if err := svc.RevokeComfyBridge(user.ID, c.Param("id")); err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
@@ -97,10 +93,6 @@ func RegisterComfyBridgeRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
if err := svc.RequireWorkflowPluginForInterface("comfyui-bridge-image"); err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
wait, err := comfyBridgeWait(c.Query("wait"))
|
||||
if err != nil {
|
||||
fail(c, http.StatusBadRequest, err)
|
||||
@@ -122,10 +114,6 @@ func RegisterComfyBridgeRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
if err := svc.RequireWorkflowPluginForInterface("comfyui-bridge-image"); err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
if c.Request.ContentLength > maxComfyBridgeRequestBytes {
|
||||
fail(c, http.StatusRequestEntityTooLarge, errors.New("Bridge 结果请求体超过 64MB"))
|
||||
return
|
||||
@@ -163,10 +151,6 @@ func RegisterComfyBridgeRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
if err := svc.RequireWorkflowPluginForInterface("comfyui-bridge-image"); err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
var req struct {
|
||||
Capabilities map[string]any `json:"capabilities,omitempty"`
|
||||
}
|
||||
|
||||
@@ -16,11 +16,56 @@ import (
|
||||
func RegisterPluginRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
statusRoutes := r.Group("/plugins")
|
||||
statusRoutes.GET("/status", func(c *gin.Context) {
|
||||
if _, err := currentUser(c, svc); err != nil {
|
||||
user, err := currentUser(c, svc)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
ok(c, gin.H{"statuses": svc.WorkflowPluginStatuses()})
|
||||
states, err := svc.PluginStatesForUser(user)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
statuses, err := svc.WorkflowPluginStatusesForUser(user.ID)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
ok(c, gin.H{"statuses": statuses, "states": states})
|
||||
})
|
||||
adminRoutes := r.Group("/admin/plugins")
|
||||
adminRoutes.GET("", func(c *gin.Context) {
|
||||
user, err := currentUser(c, svc)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
states, err := svc.AdminPluginStates(user)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
ok(c, gin.H{"plugins": svc.Plugins(), "states": states})
|
||||
})
|
||||
adminRoutes.PUT("/:id/availability", func(c *gin.Context) {
|
||||
user, err := currentUser(c, svc)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
var request struct {
|
||||
Available bool `json:"available"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
fail(c, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
state, err := svc.SetPluginPlatformAvailability(user, c.Param("id"), request.Available)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
ok(c, gin.H{"state": state})
|
||||
})
|
||||
pluginRoutes := r.Group("/plugins")
|
||||
pluginRoutes.Use(requirePluginCenterAccess(svc))
|
||||
@@ -37,7 +82,12 @@ func RegisterPluginRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
ok(c, gin.H{"plugins": plugins})
|
||||
states, err := svc.PluginStatesForUser(user)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
ok(c, gin.H{"plugins": plugins, "states": states})
|
||||
})
|
||||
pluginRoutes.GET("/catalog", func(c *gin.Context) {
|
||||
if _, err := currentUser(c, svc); err != nil {
|
||||
@@ -77,7 +127,7 @@ func RegisterPluginRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
fail(c, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
plugin, err := svc.InstallPlugin(data, fileName)
|
||||
plugin, err := svc.InstallPluginForAdmin(user, data, fileName)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
@@ -85,10 +135,27 @@ func RegisterPluginRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
ok(c, gin.H{"plugin": plugin})
|
||||
})
|
||||
pluginRoutes.GET("/:id/package", func(c *gin.Context) {
|
||||
if _, err := currentUser(c, svc); err != nil {
|
||||
user, err := currentUser(c, svc)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
visiblePlugins, err := svc.PluginsForUser(user)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
visible := false
|
||||
for _, plugin := range visiblePlugins {
|
||||
if plugin.Manifest.ID == c.Param("id") {
|
||||
visible = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !visible {
|
||||
failService(c, service.Forbidden("无权访问该插件包"))
|
||||
return
|
||||
}
|
||||
data, fileName, err := svc.PluginPackage(c.Param("id"))
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
@@ -103,6 +170,26 @@ func RegisterPluginRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
})
|
||||
pluginRoutes.POST("/:id/enable", pluginToggle(svc, true))
|
||||
pluginRoutes.POST("/:id/disable", pluginToggle(svc, false))
|
||||
pluginRoutes.PUT("/:id/activation", func(c *gin.Context) {
|
||||
user, err := currentUser(c, svc)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
var request struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
fail(c, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
state, err := svc.SetUserPluginEnabled(user, c.Param("id"), request.Enabled)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
ok(c, gin.H{"state": state})
|
||||
})
|
||||
pluginRoutes.DELETE("/:id", func(c *gin.Context) {
|
||||
user, err := currentUser(c, svc)
|
||||
if err != nil {
|
||||
@@ -113,7 +200,7 @@ func RegisterPluginRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
if err := svc.UninstallPlugin(c.Param("id")); err != nil {
|
||||
if err := svc.UninstallPluginForAdmin(user, c.Param("id")); err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
@@ -121,8 +208,7 @@ func RegisterPluginRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
})
|
||||
|
||||
pluginRoutes.GET("/eagle/library", func(c *gin.Context) {
|
||||
if _, err := currentUser(c, svc); err != nil {
|
||||
failService(c, err)
|
||||
if _, allowed := requireEnabledPlugin(c, svc, service.PluginEagleAssetConnector); !allowed {
|
||||
return
|
||||
}
|
||||
library, err := svc.EagleLibrary(c.Query("baseUrl"))
|
||||
@@ -134,8 +220,7 @@ func RegisterPluginRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
ok(c, gin.H{"library": library})
|
||||
})
|
||||
pluginRoutes.GET("/eagle/items", func(c *gin.Context) {
|
||||
if _, err := currentUser(c, svc); err != nil {
|
||||
failService(c, err)
|
||||
if _, allowed := requireEnabledPlugin(c, svc, service.PluginEagleAssetConnector); !allowed {
|
||||
return
|
||||
}
|
||||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "60"))
|
||||
@@ -148,8 +233,7 @@ func RegisterPluginRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
ok(c, gin.H{"items": items})
|
||||
})
|
||||
pluginRoutes.GET("/eagle/items/:itemId/file", func(c *gin.Context) {
|
||||
if _, err := currentUser(c, svc); err != nil {
|
||||
failService(c, err)
|
||||
if _, allowed := requireEnabledPlugin(c, svc, service.PluginEagleAssetConnector); !allowed {
|
||||
return
|
||||
}
|
||||
file, err := svc.OpenEagleItemFile(c.Query("baseUrl"), c.Param("itemId"))
|
||||
@@ -164,8 +248,7 @@ func RegisterPluginRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
c.DataFromReader(http.StatusOK, file.Size, file.MimeType, file.Body, nil)
|
||||
})
|
||||
pluginRoutes.GET("/eagle/items/:itemId/thumbnail", func(c *gin.Context) {
|
||||
if _, err := currentUser(c, svc); err != nil {
|
||||
failService(c, err)
|
||||
if _, allowed := requireEnabledPlugin(c, svc, service.PluginEagleAssetConnector); !allowed {
|
||||
return
|
||||
}
|
||||
file, err := svc.OpenEagleItemThumbnail(c.Query("baseUrl"), c.Param("itemId"))
|
||||
@@ -179,8 +262,7 @@ func RegisterPluginRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
c.DataFromReader(http.StatusOK, file.Size, file.MimeType, file.Body, nil)
|
||||
})
|
||||
pluginRoutes.POST("/eagle/items", func(c *gin.Context) {
|
||||
if _, err := currentUser(c, svc); err != nil {
|
||||
failService(c, err)
|
||||
if _, allowed := requireEnabledPlugin(c, svc, service.PluginEagleAssetConnector); !allowed {
|
||||
return
|
||||
}
|
||||
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 160<<20)
|
||||
@@ -197,8 +279,7 @@ func RegisterPluginRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
ok(c, gin.H{"item": item})
|
||||
})
|
||||
pluginRoutes.POST("/eagle/folders", func(c *gin.Context) {
|
||||
if _, err := currentUser(c, svc); err != nil {
|
||||
failService(c, err)
|
||||
if _, allowed := requireEnabledPlugin(c, svc, service.PluginEagleAssetConnector); !allowed {
|
||||
return
|
||||
}
|
||||
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 16<<10)
|
||||
@@ -250,11 +331,23 @@ func pluginToggle(svc *service.Service, enabled bool) gin.HandlerFunc {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
plugin, err := svc.SetPluginEnabled(c.Param("id"), enabled)
|
||||
state, err := svc.SetPluginPlatformAvailability(user, c.Param("id"), enabled)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
ok(c, gin.H{"plugin": plugin})
|
||||
ok(c, gin.H{"state": state})
|
||||
}
|
||||
}
|
||||
|
||||
func requireEnabledPlugin(c *gin.Context, svc *service.Service, pluginID string) (*model.User, bool) {
|
||||
user, err := currentUser(c, svc)
|
||||
if err == nil {
|
||||
err = svc.RequirePluginForUser(user.ID, pluginID)
|
||||
}
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return nil, false
|
||||
}
|
||||
return user, true
|
||||
}
|
||||
|
||||
@@ -11,11 +11,12 @@ import (
|
||||
// RegisterRunningHubRoutes 是独立工作流 Provider 的管理代理,不复用 ModelChannel。
|
||||
func RegisterRunningHubRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
fetch := func(c *gin.Context, app bool) {
|
||||
if _, err := currentUser(c, svc); err != nil {
|
||||
user, err := currentUser(c, svc)
|
||||
if err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
if err := svc.RequireWorkflowPluginForInterface("runninghub-workflow-image"); err != nil {
|
||||
if err := svc.RequireWorkflowPluginForUser(user.ID, "runninghub-workflow-image"); err != nil {
|
||||
failService(c, err)
|
||||
return
|
||||
}
|
||||
@@ -26,7 +27,6 @@ func RegisterRunningHubRoutes(r *gin.RouterGroup, svc *service.Service) {
|
||||
return
|
||||
}
|
||||
var result map[string]any
|
||||
var err error
|
||||
if app {
|
||||
result, err = svc.FetchRunningHubAppInfo(c.Request.Context(), req)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user