Files
omega-server/local/model/permission.go
Fran Jurmanović 016728532c init bootstrap
2025-07-06 15:02:09 +02:00

277 lines
7.2 KiB
Go

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"`
DateCreated string `json:"dateCreated"`
}
// 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,
DateCreated: p.DateCreated.Format("2006-01-02T15:04:05Z"),
}
}
// 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",
}