diff options
Diffstat (limited to 'weed/admin/handlers')
| -rw-r--r-- | weed/admin/handlers/admin_handlers.go | 27 | ||||
| -rw-r--r-- | weed/admin/handlers/file_browser_handlers.go | 15 | ||||
| -rw-r--r-- | weed/admin/handlers/maintenance_handlers.go | 233 | ||||
| -rw-r--r-- | weed/admin/handlers/policy_handlers.go | 273 |
4 files changed, 419 insertions, 129 deletions
diff --git a/weed/admin/handlers/admin_handlers.go b/weed/admin/handlers/admin_handlers.go index dc7905bc1..76a123a4f 100644 --- a/weed/admin/handlers/admin_handlers.go +++ b/weed/admin/handlers/admin_handlers.go @@ -17,6 +17,7 @@ type AdminHandlers struct { clusterHandlers *ClusterHandlers fileBrowserHandlers *FileBrowserHandlers userHandlers *UserHandlers + policyHandlers *PolicyHandlers maintenanceHandlers *MaintenanceHandlers mqHandlers *MessageQueueHandlers } @@ -27,6 +28,7 @@ func NewAdminHandlers(adminServer *dash.AdminServer) *AdminHandlers { clusterHandlers := NewClusterHandlers(adminServer) fileBrowserHandlers := NewFileBrowserHandlers(adminServer) userHandlers := NewUserHandlers(adminServer) + policyHandlers := NewPolicyHandlers(adminServer) maintenanceHandlers := NewMaintenanceHandlers(adminServer) mqHandlers := NewMessageQueueHandlers(adminServer) return &AdminHandlers{ @@ -35,6 +37,7 @@ func NewAdminHandlers(adminServer *dash.AdminServer) *AdminHandlers { clusterHandlers: clusterHandlers, fileBrowserHandlers: fileBrowserHandlers, userHandlers: userHandlers, + policyHandlers: policyHandlers, maintenanceHandlers: maintenanceHandlers, mqHandlers: mqHandlers, } @@ -63,6 +66,7 @@ func (h *AdminHandlers) SetupRoutes(r *gin.Engine, authRequired bool, username, protected.GET("/object-store/buckets", h.ShowS3Buckets) protected.GET("/object-store/buckets/:bucket", h.ShowBucketDetails) protected.GET("/object-store/users", h.userHandlers.ShowObjectStoreUsers) + protected.GET("/object-store/policies", h.policyHandlers.ShowPolicies) // File browser routes protected.GET("/files", h.fileBrowserHandlers.ShowFileBrowser) @@ -121,6 +125,17 @@ func (h *AdminHandlers) SetupRoutes(r *gin.Engine, authRequired bool, username, usersApi.PUT("/:username/policies", h.userHandlers.UpdateUserPolicies) } + // Object Store Policy management API routes + objectStorePoliciesApi := api.Group("/object-store/policies") + { + objectStorePoliciesApi.GET("", h.policyHandlers.GetPolicies) + objectStorePoliciesApi.POST("", h.policyHandlers.CreatePolicy) + objectStorePoliciesApi.GET("/:name", h.policyHandlers.GetPolicy) + objectStorePoliciesApi.PUT("/:name", h.policyHandlers.UpdatePolicy) + objectStorePoliciesApi.DELETE("/:name", h.policyHandlers.DeletePolicy) + objectStorePoliciesApi.POST("/validate", h.policyHandlers.ValidatePolicy) + } + // File management API routes filesApi := api.Group("/files") { @@ -171,6 +186,7 @@ func (h *AdminHandlers) SetupRoutes(r *gin.Engine, authRequired bool, username, r.GET("/object-store/buckets", h.ShowS3Buckets) r.GET("/object-store/buckets/:bucket", h.ShowBucketDetails) r.GET("/object-store/users", h.userHandlers.ShowObjectStoreUsers) + r.GET("/object-store/policies", h.policyHandlers.ShowPolicies) // File browser routes r.GET("/files", h.fileBrowserHandlers.ShowFileBrowser) @@ -229,6 +245,17 @@ func (h *AdminHandlers) SetupRoutes(r *gin.Engine, authRequired bool, username, usersApi.PUT("/:username/policies", h.userHandlers.UpdateUserPolicies) } + // Object Store Policy management API routes + objectStorePoliciesApi := api.Group("/object-store/policies") + { + objectStorePoliciesApi.GET("", h.policyHandlers.GetPolicies) + objectStorePoliciesApi.POST("", h.policyHandlers.CreatePolicy) + objectStorePoliciesApi.GET("/:name", h.policyHandlers.GetPolicy) + objectStorePoliciesApi.PUT("/:name", h.policyHandlers.UpdatePolicy) + objectStorePoliciesApi.DELETE("/:name", h.policyHandlers.DeletePolicy) + objectStorePoliciesApi.POST("/validate", h.policyHandlers.ValidatePolicy) + } + // File management API routes filesApi := api.Group("/files") { diff --git a/weed/admin/handlers/file_browser_handlers.go b/weed/admin/handlers/file_browser_handlers.go index 97621192e..c8e117041 100644 --- a/weed/admin/handlers/file_browser_handlers.go +++ b/weed/admin/handlers/file_browser_handlers.go @@ -8,6 +8,7 @@ import ( "mime/multipart" "net" "net/http" + "os" "path/filepath" "strconv" "strings" @@ -190,7 +191,7 @@ func (h *FileBrowserHandlers) CreateFolder(c *gin.Context) { Name: filepath.Base(fullPath), IsDirectory: true, Attributes: &filer_pb.FuseAttributes{ - FileMode: uint32(0755 | (1 << 31)), // Directory mode + FileMode: uint32(0755 | os.ModeDir), // Directory mode Uid: filer_pb.OS_UID, Gid: filer_pb.OS_GID, Crtime: time.Now().Unix(), @@ -656,8 +657,9 @@ func (h *FileBrowserHandlers) GetFileProperties(c *gin.Context) { properties["created_timestamp"] = entry.Attributes.Crtime } - properties["file_mode"] = fmt.Sprintf("%o", entry.Attributes.FileMode) - properties["file_mode_formatted"] = h.formatFileMode(entry.Attributes.FileMode) + properties["file_mode"] = dash.FormatFileMode(entry.Attributes.FileMode) + properties["file_mode_formatted"] = dash.FormatFileMode(entry.Attributes.FileMode) + properties["file_mode_octal"] = fmt.Sprintf("%o", entry.Attributes.FileMode) properties["uid"] = entry.Attributes.Uid properties["gid"] = entry.Attributes.Gid properties["ttl_seconds"] = entry.Attributes.TtlSec @@ -725,13 +727,6 @@ func (h *FileBrowserHandlers) formatBytes(bytes int64) string { return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp]) } -// Helper function to format file mode -func (h *FileBrowserHandlers) formatFileMode(mode uint32) string { - // Convert to octal and format as rwx permissions - perm := mode & 0777 - return fmt.Sprintf("%03o", perm) -} - // Helper function to determine MIME type from filename func (h *FileBrowserHandlers) determineMimeType(filename string) string { ext := strings.ToLower(filepath.Ext(filename)) diff --git a/weed/admin/handlers/maintenance_handlers.go b/weed/admin/handlers/maintenance_handlers.go index 954874c14..4b1f91387 100644 --- a/weed/admin/handlers/maintenance_handlers.go +++ b/weed/admin/handlers/maintenance_handlers.go @@ -11,9 +11,6 @@ import ( "github.com/seaweedfs/seaweedfs/weed/admin/view/components" "github.com/seaweedfs/seaweedfs/weed/admin/view/layout" "github.com/seaweedfs/seaweedfs/weed/worker/tasks" - "github.com/seaweedfs/seaweedfs/weed/worker/tasks/balance" - "github.com/seaweedfs/seaweedfs/weed/worker/tasks/erasure_coding" - "github.com/seaweedfs/seaweedfs/weed/worker/tasks/vacuum" "github.com/seaweedfs/seaweedfs/weed/worker/types" ) @@ -114,59 +111,60 @@ func (h *MaintenanceHandlers) ShowTaskConfig(c *gin.Context) { return } - // Try to get templ UI provider first - templUIProvider := getTemplUIProvider(taskType) + // Try to get templ UI provider first - temporarily disabled + // templUIProvider := getTemplUIProvider(taskType) var configSections []components.ConfigSectionData - if templUIProvider != nil { - // Use the new templ-based UI provider - currentConfig := templUIProvider.GetCurrentConfig() - sections, err := templUIProvider.RenderConfigSections(currentConfig) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to render configuration sections: " + err.Error()}) - return - } - configSections = sections - } else { - // Fallback to basic configuration for providers that haven't been migrated yet - configSections = []components.ConfigSectionData{ - { - Title: "Configuration Settings", - Icon: "fas fa-cogs", - Description: "Configure task detection and scheduling parameters", - Fields: []interface{}{ - components.CheckboxFieldData{ - FormFieldData: components.FormFieldData{ - Name: "enabled", - Label: "Enable Task", - Description: "Whether this task type should be enabled", - }, - Checked: true, + // Temporarily disabled templ UI provider + // if templUIProvider != nil { + // // Use the new templ-based UI provider + // currentConfig := templUIProvider.GetCurrentConfig() + // sections, err := templUIProvider.RenderConfigSections(currentConfig) + // if err != nil { + // c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to render configuration sections: " + err.Error()}) + // return + // } + // configSections = sections + // } else { + // Fallback to basic configuration for providers that haven't been migrated yet + configSections = []components.ConfigSectionData{ + { + Title: "Configuration Settings", + Icon: "fas fa-cogs", + Description: "Configure task detection and scheduling parameters", + Fields: []interface{}{ + components.CheckboxFieldData{ + FormFieldData: components.FormFieldData{ + Name: "enabled", + Label: "Enable Task", + Description: "Whether this task type should be enabled", }, - components.NumberFieldData{ - FormFieldData: components.FormFieldData{ - Name: "max_concurrent", - Label: "Max Concurrent Tasks", - Description: "Maximum number of concurrent tasks", - Required: true, - }, - Value: 2, - Step: "1", - Min: floatPtr(1), + Checked: true, + }, + components.NumberFieldData{ + FormFieldData: components.FormFieldData{ + Name: "max_concurrent", + Label: "Max Concurrent Tasks", + Description: "Maximum number of concurrent tasks", + Required: true, }, - components.DurationFieldData{ - FormFieldData: components.FormFieldData{ - Name: "scan_interval", - Label: "Scan Interval", - Description: "How often to scan for tasks", - Required: true, - }, - Value: "30m", + Value: 2, + Step: "1", + Min: floatPtr(1), + }, + components.DurationFieldData{ + FormFieldData: components.FormFieldData{ + Name: "scan_interval", + Label: "Scan Interval", + Description: "How often to scan for tasks", + Required: true, }, + Value: "30m", }, }, - } + }, } + // } // End of disabled templ UI provider else block // Create task configuration data using templ components configData := &app.TaskConfigTemplData{ @@ -199,8 +197,8 @@ func (h *MaintenanceHandlers) UpdateTaskConfig(c *gin.Context) { return } - // Try to get templ UI provider first - templUIProvider := getTemplUIProvider(taskType) + // Try to get templ UI provider first - temporarily disabled + // templUIProvider := getTemplUIProvider(taskType) // Parse form data err := c.Request.ParseForm() @@ -217,52 +215,53 @@ func (h *MaintenanceHandlers) UpdateTaskConfig(c *gin.Context) { var config interface{} - if templUIProvider != nil { - // Use the new templ-based UI provider - config, err = templUIProvider.ParseConfigForm(formData) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse configuration: " + err.Error()}) - return - } + // Temporarily disabled templ UI provider + // if templUIProvider != nil { + // // Use the new templ-based UI provider + // config, err = templUIProvider.ParseConfigForm(formData) + // if err != nil { + // c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse configuration: " + err.Error()}) + // return + // } + // // Apply configuration using templ provider + // err = templUIProvider.ApplyConfig(config) + // if err != nil { + // c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to apply configuration: " + err.Error()}) + // return + // } + // } else { + // Fallback to old UI provider for tasks that haven't been migrated yet + // Fallback to old UI provider for tasks that haven't been migrated yet + uiRegistry := tasks.GetGlobalUIRegistry() + typesRegistry := tasks.GetGlobalTypesRegistry() - // Apply configuration using templ provider - err = templUIProvider.ApplyConfig(config) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to apply configuration: " + err.Error()}) - return - } - } else { - // Fallback to old UI provider for tasks that haven't been migrated yet - uiRegistry := tasks.GetGlobalUIRegistry() - typesRegistry := tasks.GetGlobalTypesRegistry() - - var provider types.TaskUIProvider - for workerTaskType := range typesRegistry.GetAllDetectors() { - if string(workerTaskType) == string(taskType) { - provider = uiRegistry.GetProvider(workerTaskType) - break - } + var provider types.TaskUIProvider + for workerTaskType := range typesRegistry.GetAllDetectors() { + if string(workerTaskType) == string(taskType) { + provider = uiRegistry.GetProvider(workerTaskType) + break } + } - if provider == nil { - c.JSON(http.StatusNotFound, gin.H{"error": "UI provider not found for task type"}) - return - } + if provider == nil { + c.JSON(http.StatusNotFound, gin.H{"error": "UI provider not found for task type"}) + return + } - // Parse configuration from form using old provider - config, err = provider.ParseConfigForm(formData) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse configuration: " + err.Error()}) - return - } + // Parse configuration from form using old provider + config, err = provider.ParseConfigForm(formData) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse configuration: " + err.Error()}) + return + } - // Apply configuration using old provider - err = provider.ApplyConfig(config) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to apply configuration: " + err.Error()}) - return - } + // Apply configuration using old provider + err = provider.ApplyConfig(config) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to apply configuration: " + err.Error()}) + return } + // } // End of disabled templ UI provider else block // Redirect back to task configuration page c.Redirect(http.StatusSeeOther, "/maintenance/config/"+taskTypeName) @@ -350,39 +349,35 @@ func floatPtr(f float64) *float64 { return &f } -// Global templ UI registry -var globalTemplUIRegistry *types.UITemplRegistry +// Global templ UI registry - temporarily disabled +// var globalTemplUIRegistry *types.UITemplRegistry -// initTemplUIRegistry initializes the global templ UI registry +// initTemplUIRegistry initializes the global templ UI registry - temporarily disabled func initTemplUIRegistry() { - if globalTemplUIRegistry == nil { - globalTemplUIRegistry = types.NewUITemplRegistry() - - // Register vacuum templ UI provider using shared instances - vacuumDetector, vacuumScheduler := vacuum.GetSharedInstances() - vacuum.RegisterUITempl(globalTemplUIRegistry, vacuumDetector, vacuumScheduler) - - // Register erasure coding templ UI provider using shared instances - erasureCodingDetector, erasureCodingScheduler := erasure_coding.GetSharedInstances() - erasure_coding.RegisterUITempl(globalTemplUIRegistry, erasureCodingDetector, erasureCodingScheduler) - - // Register balance templ UI provider using shared instances - balanceDetector, balanceScheduler := balance.GetSharedInstances() - balance.RegisterUITempl(globalTemplUIRegistry, balanceDetector, balanceScheduler) - } + // Temporarily disabled due to missing types + // if globalTemplUIRegistry == nil { + // globalTemplUIRegistry = types.NewUITemplRegistry() + // // Register vacuum templ UI provider using shared instances + // vacuumDetector, vacuumScheduler := vacuum.GetSharedInstances() + // vacuum.RegisterUITempl(globalTemplUIRegistry, vacuumDetector, vacuumScheduler) + // // Register erasure coding templ UI provider using shared instances + // erasureCodingDetector, erasureCodingScheduler := erasure_coding.GetSharedInstances() + // erasure_coding.RegisterUITempl(globalTemplUIRegistry, erasureCodingDetector, erasureCodingScheduler) + // // Register balance templ UI provider using shared instances + // balanceDetector, balanceScheduler := balance.GetSharedInstances() + // balance.RegisterUITempl(globalTemplUIRegistry, balanceDetector, balanceScheduler) + // } } -// getTemplUIProvider gets the templ UI provider for a task type -func getTemplUIProvider(taskType maintenance.MaintenanceTaskType) types.TaskUITemplProvider { - initTemplUIRegistry() - +// getTemplUIProvider gets the templ UI provider for a task type - temporarily disabled +func getTemplUIProvider(taskType maintenance.MaintenanceTaskType) interface{} { + // initTemplUIRegistry() // Convert maintenance task type to worker task type - typesRegistry := tasks.GetGlobalTypesRegistry() - for workerTaskType := range typesRegistry.GetAllDetectors() { - if string(workerTaskType) == string(taskType) { - return globalTemplUIRegistry.GetProvider(workerTaskType) - } - } - + // typesRegistry := tasks.GetGlobalTypesRegistry() + // for workerTaskType := range typesRegistry.GetAllDetectors() { + // if string(workerTaskType) == string(taskType) { + // return globalTemplUIRegistry.GetProvider(workerTaskType) + // } + // } return nil } diff --git a/weed/admin/handlers/policy_handlers.go b/weed/admin/handlers/policy_handlers.go new file mode 100644 index 000000000..8f5cc91b1 --- /dev/null +++ b/weed/admin/handlers/policy_handlers.go @@ -0,0 +1,273 @@ +package handlers + +import ( + "fmt" + "net/http" + "time" + + "github.com/gin-gonic/gin" + "github.com/seaweedfs/seaweedfs/weed/admin/dash" + "github.com/seaweedfs/seaweedfs/weed/admin/view/app" + "github.com/seaweedfs/seaweedfs/weed/admin/view/layout" + "github.com/seaweedfs/seaweedfs/weed/credential" + "github.com/seaweedfs/seaweedfs/weed/glog" +) + +// PolicyHandlers contains all the HTTP handlers for policy management +type PolicyHandlers struct { + adminServer *dash.AdminServer +} + +// NewPolicyHandlers creates a new instance of PolicyHandlers +func NewPolicyHandlers(adminServer *dash.AdminServer) *PolicyHandlers { + return &PolicyHandlers{ + adminServer: adminServer, + } +} + +// ShowPolicies renders the policies management page +func (h *PolicyHandlers) ShowPolicies(c *gin.Context) { + // Get policies data from the server + policiesData := h.getPoliciesData(c) + + // Render HTML template + c.Header("Content-Type", "text/html") + policiesComponent := app.Policies(policiesData) + layoutComponent := layout.Layout(c, policiesComponent) + err := layoutComponent.Render(c.Request.Context(), c.Writer) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to render template: " + err.Error()}) + return + } +} + +// GetPolicies returns the list of policies as JSON +func (h *PolicyHandlers) GetPolicies(c *gin.Context) { + policies, err := h.adminServer.GetPolicies() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get policies: " + err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"policies": policies}) +} + +// CreatePolicy handles policy creation +func (h *PolicyHandlers) CreatePolicy(c *gin.Context) { + var req dash.CreatePolicyRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request: " + err.Error()}) + return + } + + // Validate policy name + if req.Name == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "Policy name is required"}) + return + } + + // Check if policy already exists + existingPolicy, err := h.adminServer.GetPolicy(req.Name) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check existing policy: " + err.Error()}) + return + } + if existingPolicy != nil { + c.JSON(http.StatusConflict, gin.H{"error": "Policy with this name already exists"}) + return + } + + // Create the policy + err = h.adminServer.CreatePolicy(req.Name, req.Document) + if err != nil { + glog.Errorf("Failed to create policy %s: %v", req.Name, err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create policy: " + err.Error()}) + return + } + + c.JSON(http.StatusCreated, gin.H{ + "success": true, + "message": "Policy created successfully", + "policy": req.Name, + }) +} + +// GetPolicy returns a specific policy +func (h *PolicyHandlers) GetPolicy(c *gin.Context) { + policyName := c.Param("name") + if policyName == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "Policy name is required"}) + return + } + + policy, err := h.adminServer.GetPolicy(policyName) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get policy: " + err.Error()}) + return + } + + if policy == nil { + c.JSON(http.StatusNotFound, gin.H{"error": "Policy not found"}) + return + } + + c.JSON(http.StatusOK, policy) +} + +// UpdatePolicy handles policy updates +func (h *PolicyHandlers) UpdatePolicy(c *gin.Context) { + policyName := c.Param("name") + if policyName == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "Policy name is required"}) + return + } + + var req dash.UpdatePolicyRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request: " + err.Error()}) + return + } + + // Check if policy exists + existingPolicy, err := h.adminServer.GetPolicy(policyName) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check existing policy: " + err.Error()}) + return + } + if existingPolicy == nil { + c.JSON(http.StatusNotFound, gin.H{"error": "Policy not found"}) + return + } + + // Update the policy + err = h.adminServer.UpdatePolicy(policyName, req.Document) + if err != nil { + glog.Errorf("Failed to update policy %s: %v", policyName, err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update policy: " + err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{ + "success": true, + "message": "Policy updated successfully", + "policy": policyName, + }) +} + +// DeletePolicy handles policy deletion +func (h *PolicyHandlers) DeletePolicy(c *gin.Context) { + policyName := c.Param("name") + if policyName == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "Policy name is required"}) + return + } + + // Check if policy exists + existingPolicy, err := h.adminServer.GetPolicy(policyName) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check existing policy: " + err.Error()}) + return + } + if existingPolicy == nil { + c.JSON(http.StatusNotFound, gin.H{"error": "Policy not found"}) + return + } + + // Delete the policy + err = h.adminServer.DeletePolicy(policyName) + if err != nil { + glog.Errorf("Failed to delete policy %s: %v", policyName, err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete policy: " + err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{ + "success": true, + "message": "Policy deleted successfully", + "policy": policyName, + }) +} + +// ValidatePolicy validates a policy document without saving it +func (h *PolicyHandlers) ValidatePolicy(c *gin.Context) { + var req struct { + Document credential.PolicyDocument `json:"document" binding:"required"` + } + + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request: " + err.Error()}) + return + } + + // Basic validation + if req.Document.Version == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "Policy version is required"}) + return + } + + if len(req.Document.Statement) == 0 { + c.JSON(http.StatusBadRequest, gin.H{"error": "Policy must have at least one statement"}) + return + } + + // Validate each statement + for i, statement := range req.Document.Statement { + if statement.Effect != "Allow" && statement.Effect != "Deny" { + c.JSON(http.StatusBadRequest, gin.H{ + "error": fmt.Sprintf("Statement %d: Effect must be 'Allow' or 'Deny'", i+1), + }) + return + } + + if len(statement.Action) == 0 { + c.JSON(http.StatusBadRequest, gin.H{ + "error": fmt.Sprintf("Statement %d: Action is required", i+1), + }) + return + } + + if len(statement.Resource) == 0 { + c.JSON(http.StatusBadRequest, gin.H{ + "error": fmt.Sprintf("Statement %d: Resource is required", i+1), + }) + return + } + } + + c.JSON(http.StatusOK, gin.H{ + "valid": true, + "message": "Policy document is valid", + }) +} + +// getPoliciesData retrieves policies data from the server +func (h *PolicyHandlers) getPoliciesData(c *gin.Context) dash.PoliciesData { + username := c.GetString("username") + if username == "" { + username = "admin" + } + + // Get policies + policies, err := h.adminServer.GetPolicies() + if err != nil { + glog.Errorf("Failed to get policies: %v", err) + // Return empty data on error + return dash.PoliciesData{ + Username: username, + Policies: []dash.IAMPolicy{}, + TotalPolicies: 0, + LastUpdated: time.Now(), + } + } + + // Ensure policies is never nil + if policies == nil { + policies = []dash.IAMPolicy{} + } + + return dash.PoliciesData{ + Username: username, + Policies: policies, + TotalPolicies: len(policies), + LastUpdated: time.Now(), + } +} |
