3.9 KB
acl.go
package controllers
import (
"fmt"
"net/http"
"github.com/readysite/readysite/pkg/application"
"github.com/readysite/readysite/website/internal/access"
"github.com/readysite/readysite/website/models"
)
// ACL returns the acl controller.
func ACL() (string, *ACLController) {
return "acl", &ACLController{}
}
// ACLController handles ACL management.
type ACLController struct {
application.BaseController
}
// Setup registers routes.
func (c *ACLController) Setup(app *application.App) {
c.BaseController.Setup(app)
}
// Handle implements Controller interface with value receiver for request isolation.
func (c ACLController) Handle(r *http.Request) application.Controller {
c.Request = r
return &c
}
// ResourceType returns the current resource type from the path.
func (c *ACLController) ResourceType() string {
if c.Request == nil {
return ""
}
return c.PathValue("type")
}
// ResourceID returns the current resource ID from the path.
func (c *ACLController) ResourceID() string {
if c.Request == nil {
return ""
}
return c.PathValue("id")
}
// Rules returns the ACL rules for the current resource.
func (c *ACLController) Rules() []*models.ACLRule {
rules, _ := access.GetRules(c.ResourceType(), c.ResourceID())
return rules
}
// SubjectTypes returns available subject types.
func (c *ACLController) SubjectTypes() []string {
return []string{access.SubjectUser, access.SubjectRole, access.SubjectPublic}
}
// Permissions returns available permission levels.
func (c *ACLController) Permissions() []string {
return []string{access.PermRead, access.PermWrite, access.PermDelete, access.PermAdmin}
}
// Users returns all users for user selection.
func (c *ACLController) Users() []*models.User {
users, _ := models.Users.Search("ORDER BY Email")
return users
}
// Roles returns available roles.
func (c *ACLController) Roles() []string {
return []string{access.RoleAdmin, access.RoleUser, access.RoleViewer}
}
// Create creates a new ACL rule.
func (c *ACLController) Create(w http.ResponseWriter, r *http.Request) {
resourceType := r.PathValue("type")
resourceID := r.PathValue("id")
subjectType := r.FormValue("subject_type")
subjectID := r.FormValue("subject_id")
permission := r.FormValue("permission")
if subjectType == "" || permission == "" {
c.RenderError(w, r, fmt.Errorf("Subject type and permission are required"))
return
}
// Public rules don't need a subject ID
if subjectType == access.SubjectPublic {
subjectID = ""
}
if err := access.GrantAccess(subjectType, subjectID, resourceType, resourceID, permission); err != nil {
c.RenderError(w, r, fmt.Errorf("Failed to create rule: %w", err))
return
}
c.Refresh(w, r)
}
// Delete deletes an ACL rule.
func (c *ACLController) Delete(w http.ResponseWriter, r *http.Request) {
ruleID := r.PathValue("ruleId")
rule, err := models.ACLRules.Get(ruleID)
if err != nil {
c.RenderError(w, r, fmt.Errorf("Rule not found"))
return
}
if err := models.ACLRules.Delete(rule); err != nil {
c.RenderError(w, r, fmt.Errorf("Failed to delete rule: %w", err))
return
}
c.Refresh(w, r)
}
// SubjectLabel returns a human-readable label for a subject.
func (c *ACLController) SubjectLabel(rule *models.ACLRule) string {
switch rule.SubjectType {
case access.SubjectPublic:
return "Public"
case access.SubjectRole:
return "Role: " + rule.SubjectID
case access.SubjectUser:
user, err := models.Users.Get(rule.SubjectID)
if err == nil && user != nil {
return "User: " + user.Email
}
return "User: " + rule.SubjectID
default:
return rule.SubjectType + ": " + rule.SubjectID
}
}
// PermissionLabel returns a human-readable label for a permission.
func (c *ACLController) PermissionLabel(perm string) string {
switch perm {
case access.PermRead:
return "Read"
case access.PermWrite:
return "Write"
case access.PermDelete:
return "Delete"
case access.PermAdmin:
return "Admin"
default:
return perm
}
}