package model import ( "errors" "strings" "gorm.io/gorm" ) // Role represents a role in the system type Role struct { BaseModel Name string `json:"name" gorm:"unique;not null;type:varchar(100)"` Description string `json:"description" gorm:"type:text"` Active bool `json:"active" gorm:"default:true"` System bool `json:"system" gorm:"default:false"` // System roles cannot be deleted Users []User `json:"-" gorm:"many2many:user_roles;"` Permissions []Permission `json:"permissions" gorm:"many2many:role_permissions;"` } // RoleCreateRequest represents the request to create a new role type RoleCreateRequest struct { Name string `json:"name" validate:"required,min=3,max=100"` Description string `json:"description" validate:"max=500"` PermissionIDs []string `json:"permissionIds"` } // RoleUpdateRequest represents the request to update a role type RoleUpdateRequest struct { Name *string `json:"name,omitempty" validate:"omitempty,min=3,max=100"` Description *string `json:"description,omitempty" validate:"omitempty,max=500"` Active *bool `json:"active,omitempty"` PermissionIDs []string `json:"permissionIds,omitempty"` } // RoleInfo represents public role information type RoleInfo struct { ID string `json:"id"` Name string `json:"name"` Description string `json:"description"` Active bool `json:"active"` System bool `json:"system"` Permissions []PermissionInfo `json:"permissions"` UserCount int64 `json:"userCount"` CreatedAt string `json:"created_at"` } // BeforeCreate is called before creating a role func (r *Role) BeforeCreate(tx *gorm.DB) error { r.BaseModel.BeforeCreate() // Normalize name r.Name = strings.ToLower(strings.TrimSpace(r.Name)) r.Description = strings.TrimSpace(r.Description) return r.Validate() } // BeforeUpdate is called before updating a role func (r *Role) BeforeUpdate(tx *gorm.DB) error { r.BaseModel.BeforeUpdate() // Normalize fields if they're being updated if r.Name != "" { r.Name = strings.ToLower(strings.TrimSpace(r.Name)) } if r.Description != "" { r.Description = strings.TrimSpace(r.Description) } return r.Validate() } // BeforeDelete is called before deleting a role func (r *Role) BeforeDelete(tx *gorm.DB) error { if r.System { return errors.New("system roles cannot be deleted") } // Check if role is assigned to any users var userCount int64 if err := tx.Model(&User{}).Where("roles.id = ?", r.ID).Joins("JOIN user_roles ON users.id = user_roles.user_id").Count(&userCount).Error; err != nil { return err } if userCount > 0 { return errors.New("cannot delete role that is assigned to users") } return nil } // Validate validates role data func (r *Role) Validate() error { if r.Name == "" { return errors.New("role name is required") } if len(r.Name) < 3 || len(r.Name) > 100 { return errors.New("role name must be between 3 and 100 characters") } if !isValidRoleName(r.Name) { return errors.New("role name can only contain letters, numbers, underscores, and hyphens") } if len(r.Description) > 500 { return errors.New("role description must not exceed 500 characters") } return nil } // ToRoleInfo converts Role to RoleInfo (public information) func (r *Role) ToRoleInfo() RoleInfo { roleInfo := RoleInfo{ ID: r.ID, Name: r.Name, Description: r.Description, Active: r.Active, System: r.System, Permissions: make([]PermissionInfo, len(r.Permissions)), CreatedAt: r.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), } // Convert permissions for i, permission := range r.Permissions { roleInfo.Permissions[i] = permission.ToPermissionInfo() } return roleInfo } // HasPermission checks if the role has a specific permission func (r *Role) HasPermission(permissionName string) bool { for _, permission := range r.Permissions { if permission.Name == permissionName { return true } } return false } // AddPermission adds a permission to the role func (r *Role) AddPermission(permission Permission) { if !r.HasPermission(permission.Name) { r.Permissions = append(r.Permissions, permission) } } // RemovePermission removes a permission from the role func (r *Role) RemovePermission(permissionName string) { for i, permission := range r.Permissions { if permission.Name == permissionName { r.Permissions = append(r.Permissions[:i], r.Permissions[i+1:]...) break } } } // GetPermissionNames returns a slice of permission names func (r *Role) GetPermissionNames() []string { names := make([]string, len(r.Permissions)) for i, permission := range r.Permissions { names[i] = permission.Name } return names } // isValidRoleName validates role name format func isValidRoleName(name string) bool { // Allow letters, numbers, underscores, and hyphens for _, char := range name { if !((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9') || char == '_' || char == '-') { return false } } return true }