package model import ( "errors" "strings" "gorm.io/gorm" ) // Permission represents a permission in the system type Permission struct { BaseModel Name string `json:"name" gorm:"unique;not null;type:varchar(100)"` Description string `json:"description" gorm:"type:text"` Category string `json:"category" gorm:"type:varchar(50)"` Active bool `json:"active" gorm:"default:true"` System bool `json:"system" gorm:"default:false"` // System permissions cannot be deleted Roles []Role `json:"-" gorm:"many2many:role_permissions;"` } // PermissionCreateRequest represents the request to create a new permission type PermissionCreateRequest struct { Name string `json:"name" validate:"required,min=3,max=100"` Description string `json:"description" validate:"max=500"` Category string `json:"category" validate:"required,max=50"` } // PermissionUpdateRequest represents the request to update a permission type PermissionUpdateRequest struct { Name *string `json:"name,omitempty" validate:"omitempty,min=3,max=100"` Description *string `json:"description,omitempty" validate:"omitempty,max=500"` Category *string `json:"category,omitempty" validate:"omitempty,max=50"` Active *bool `json:"active,omitempty"` } // PermissionInfo represents public permission information type PermissionInfo struct { ID string `json:"id"` Name string `json:"name"` Description string `json:"description"` Category string `json:"category"` Active bool `json:"active"` System bool `json:"system"` RoleCount int64 `json:"roleCount"` CreatedAt string `json:"created_at"` } // BeforeCreate is called before creating a permission func (p *Permission) BeforeCreate(tx *gorm.DB) error { p.BaseModel.BeforeCreate() // Normalize fields p.Name = strings.ToLower(strings.TrimSpace(p.Name)) p.Description = strings.TrimSpace(p.Description) p.Category = strings.ToLower(strings.TrimSpace(p.Category)) return p.Validate() } // BeforeUpdate is called before updating a permission func (p *Permission) BeforeUpdate(tx *gorm.DB) error { p.BaseModel.BeforeUpdate() // Normalize fields if they're being updated if p.Name != "" { p.Name = strings.ToLower(strings.TrimSpace(p.Name)) } if p.Description != "" { p.Description = strings.TrimSpace(p.Description) } if p.Category != "" { p.Category = strings.ToLower(strings.TrimSpace(p.Category)) } return p.Validate() } // BeforeDelete is called before deleting a permission func (p *Permission) BeforeDelete(tx *gorm.DB) error { if p.System { return errors.New("system permissions cannot be deleted") } // Check if permission is assigned to any roles var roleCount int64 if err := tx.Model(&Role{}).Where("permissions.id = ?", p.ID).Joins("JOIN role_permissions ON roles.id = role_permissions.role_id").Count(&roleCount).Error; err != nil { return err } if roleCount > 0 { return errors.New("cannot delete permission that is assigned to roles") } return nil } // Validate validates permission data func (p *Permission) Validate() error { if p.Name == "" { return errors.New("permission name is required") } if len(p.Name) < 3 || len(p.Name) > 100 { return errors.New("permission name must be between 3 and 100 characters") } if !isValidPermissionName(p.Name) { return errors.New("permission name must follow the format 'resource:action' (e.g., 'user:create')") } if p.Category == "" { return errors.New("permission category is required") } if len(p.Category) > 50 { return errors.New("permission category must not exceed 50 characters") } if len(p.Description) > 500 { return errors.New("permission description must not exceed 500 characters") } return nil } // ToPermissionInfo converts Permission to PermissionInfo (public information) func (p *Permission) ToPermissionInfo() PermissionInfo { return PermissionInfo{ ID: p.ID, Name: p.Name, Description: p.Description, Category: p.Category, Active: p.Active, System: p.System, CreatedAt: p.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), } } // GetResource extracts the resource part from a permission name (e.g., "user:create" -> "user") func (p *Permission) GetResource() string { parts := strings.Split(p.Name, ":") if len(parts) > 0 { return parts[0] } return "" } // GetAction extracts the action part from a permission name (e.g., "user:create" -> "create") func (p *Permission) GetAction() string { parts := strings.Split(p.Name, ":") if len(parts) > 1 { return parts[1] } return "" } // isValidPermissionName validates permission name format func isValidPermissionName(name string) bool { // Permission names should follow the format "resource:action" parts := strings.Split(name, ":") if len(parts) != 2 { return false } resource := parts[0] action := parts[1] // Validate resource part if len(resource) < 2 || len(resource) > 50 { return false } // Validate action part if len(action) < 2 || len(action) > 50 { return false } // Check if both parts contain only valid characters return isValidIdentifier(resource) && isValidIdentifier(action) } // isValidIdentifier checks if a string is a valid identifier (letters, numbers, underscores) func isValidIdentifier(str string) bool { for _, char := range str { if !((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9') || char == '_') { return false } } return true } // Common permission categories const ( PermissionCategoryUser = "user" PermissionCategoryRole = "role" PermissionCategorySystem = "system" PermissionCategoryContent = "content" PermissionCategoryReport = "report" ) // Common permission patterns const ( PermissionCreate = "create" PermissionRead = "read" PermissionUpdate = "update" PermissionDelete = "delete" PermissionManage = "manage" PermissionAdmin = "admin" ) // GetStandardPermissions returns a list of standard permissions for a resource func GetStandardPermissions(resource string) []Permission { return []Permission{ { Name: resource + ":" + PermissionCreate, Description: "Create new " + resource + " records", Category: resource, Active: true, }, { Name: resource + ":" + PermissionRead, Description: "Read " + resource + " records", Category: resource, Active: true, }, { Name: resource + ":" + PermissionUpdate, Description: "Update " + resource + " records", Category: resource, Active: true, }, { Name: resource + ":" + PermissionDelete, Description: "Delete " + resource + " records", Category: resource, Active: true, }, } } // Common system permissions const ( ServerView = "server:view" ServerUpdate = "server:update" ServerStart = "server:start" ServerStop = "server:stop" ConfigView = "config:view" ConfigUpdate = "config:update" ) // AllPermissions returns all available permissions in the system var AllPermissions = []string{ "user:create", "user:read", "user:update", "user:delete", "role:create", "role:read", "role:update", "role:delete", "permission:create", "permission:read", "permission:update", "permission:delete", ServerView, ServerUpdate, ServerStart, ServerStop, ConfigView, ConfigUpdate, "audit:read", "system:admin", }