init bootstrap
This commit is contained in:
280
local/model/system_config.go
Normal file
280
local/model/system_config.go
Normal file
@@ -0,0 +1,280 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// SystemConfig represents a system configuration setting
|
||||
type SystemConfig struct {
|
||||
BaseModel
|
||||
Key string `json:"key" gorm:"unique;not null;type:varchar(255)"`
|
||||
Value string `json:"value" gorm:"type:text"`
|
||||
DefaultValue string `json:"defaultValue" gorm:"type:text"`
|
||||
Description string `json:"description" gorm:"type:text"`
|
||||
Category string `json:"category" gorm:"type:varchar(100)"`
|
||||
DataType string `json:"dataType" gorm:"type:varchar(50)"` // string, integer, boolean, json
|
||||
IsEditable bool `json:"isEditable" gorm:"default:true"`
|
||||
IsSecret bool `json:"isSecret" gorm:"default:false"` // For sensitive values
|
||||
DateModified string `json:"dateModified" gorm:"type:varchar(50)"`
|
||||
}
|
||||
|
||||
// SystemConfigCreateRequest represents the request to create a new system config
|
||||
type SystemConfigCreateRequest struct {
|
||||
Key string `json:"key" validate:"required,min=3,max=255"`
|
||||
Value string `json:"value"`
|
||||
DefaultValue string `json:"defaultValue"`
|
||||
Description string `json:"description" validate:"max=1000"`
|
||||
Category string `json:"category" validate:"required,max=100"`
|
||||
DataType string `json:"dataType" validate:"required,oneof=string integer boolean json"`
|
||||
IsEditable bool `json:"isEditable"`
|
||||
IsSecret bool `json:"isSecret"`
|
||||
}
|
||||
|
||||
// SystemConfigUpdateRequest represents the request to update a system config
|
||||
type SystemConfigUpdateRequest struct {
|
||||
Value *string `json:"value,omitempty"`
|
||||
Description *string `json:"description,omitempty" validate:"omitempty,max=1000"`
|
||||
Category *string `json:"category,omitempty" validate:"omitempty,max=100"`
|
||||
DataType *string `json:"dataType,omitempty" validate:"omitempty,oneof=string integer boolean json"`
|
||||
IsEditable *bool `json:"isEditable,omitempty"`
|
||||
IsSecret *bool `json:"isSecret,omitempty"`
|
||||
}
|
||||
|
||||
// SystemConfigInfo represents public system config information
|
||||
type SystemConfigInfo struct {
|
||||
ID string `json:"id"`
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value,omitempty"` // Omitted if secret
|
||||
DefaultValue string `json:"defaultValue,omitempty"`
|
||||
Description string `json:"description"`
|
||||
Category string `json:"category"`
|
||||
DataType string `json:"dataType"`
|
||||
IsEditable bool `json:"isEditable"`
|
||||
IsSecret bool `json:"isSecret"`
|
||||
DateCreated string `json:"dateCreated"`
|
||||
DateModified string `json:"dateModified"`
|
||||
}
|
||||
|
||||
// BeforeCreate is called before creating a system config
|
||||
func (sc *SystemConfig) BeforeCreate(tx *gorm.DB) error {
|
||||
sc.BaseModel.BeforeCreate()
|
||||
|
||||
// Normalize key and category
|
||||
sc.Key = strings.ToLower(strings.TrimSpace(sc.Key))
|
||||
sc.Category = strings.ToLower(strings.TrimSpace(sc.Category))
|
||||
sc.Description = strings.TrimSpace(sc.Description)
|
||||
sc.DateModified = time.Now().UTC().Format(time.RFC3339)
|
||||
|
||||
return sc.Validate()
|
||||
}
|
||||
|
||||
// BeforeUpdate is called before updating a system config
|
||||
func (sc *SystemConfig) BeforeUpdate(tx *gorm.DB) error {
|
||||
sc.BaseModel.BeforeUpdate()
|
||||
|
||||
// Update modification timestamp
|
||||
sc.DateModified = time.Now().UTC().Format(time.RFC3339)
|
||||
|
||||
// Normalize fields if they're being updated
|
||||
if sc.Key != "" {
|
||||
sc.Key = strings.ToLower(strings.TrimSpace(sc.Key))
|
||||
}
|
||||
if sc.Category != "" {
|
||||
sc.Category = strings.ToLower(strings.TrimSpace(sc.Category))
|
||||
}
|
||||
if sc.Description != "" {
|
||||
sc.Description = strings.TrimSpace(sc.Description)
|
||||
}
|
||||
|
||||
return sc.Validate()
|
||||
}
|
||||
|
||||
// Validate validates system config data
|
||||
func (sc *SystemConfig) Validate() error {
|
||||
if sc.Key == "" {
|
||||
return errors.New("configuration key is required")
|
||||
}
|
||||
|
||||
if len(sc.Key) < 3 || len(sc.Key) > 255 {
|
||||
return errors.New("configuration key must be between 3 and 255 characters")
|
||||
}
|
||||
|
||||
if !isValidConfigKey(sc.Key) {
|
||||
return errors.New("configuration key can only contain letters, numbers, dots, underscores, and hyphens")
|
||||
}
|
||||
|
||||
if sc.Category == "" {
|
||||
return errors.New("configuration category is required")
|
||||
}
|
||||
|
||||
if len(sc.Category) > 100 {
|
||||
return errors.New("configuration category must not exceed 100 characters")
|
||||
}
|
||||
|
||||
if sc.DataType == "" {
|
||||
return errors.New("configuration data type is required")
|
||||
}
|
||||
|
||||
if !isValidDataType(sc.DataType) {
|
||||
return errors.New("invalid data type, must be one of: string, integer, boolean, json")
|
||||
}
|
||||
|
||||
if len(sc.Description) > 1000 {
|
||||
return errors.New("configuration description must not exceed 1000 characters")
|
||||
}
|
||||
|
||||
// Validate value according to data type
|
||||
if sc.Value != "" {
|
||||
if err := sc.ValidateValue(sc.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateValue validates the configuration value according to its data type
|
||||
func (sc *SystemConfig) ValidateValue(value string) error {
|
||||
switch sc.DataType {
|
||||
case "integer":
|
||||
if _, err := strconv.Atoi(value); err != nil {
|
||||
return errors.New("value must be a valid integer")
|
||||
}
|
||||
case "boolean":
|
||||
if _, err := strconv.ParseBool(value); err != nil {
|
||||
return errors.New("value must be a valid boolean (true/false)")
|
||||
}
|
||||
case "json":
|
||||
// Basic JSON validation - check if it starts with { or [
|
||||
trimmed := strings.TrimSpace(value)
|
||||
if !strings.HasPrefix(trimmed, "{") && !strings.HasPrefix(trimmed, "[") {
|
||||
return errors.New("value must be valid JSON")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToSystemConfigInfo converts SystemConfig to SystemConfigInfo (public information)
|
||||
func (sc *SystemConfig) ToSystemConfigInfo() SystemConfigInfo {
|
||||
info := SystemConfigInfo{
|
||||
ID: sc.ID,
|
||||
Key: sc.Key,
|
||||
DefaultValue: sc.DefaultValue,
|
||||
Description: sc.Description,
|
||||
Category: sc.Category,
|
||||
DataType: sc.DataType,
|
||||
IsEditable: sc.IsEditable,
|
||||
IsSecret: sc.IsSecret,
|
||||
DateCreated: sc.DateCreated.Format("2006-01-02T15:04:05Z"),
|
||||
DateModified: sc.DateModified,
|
||||
}
|
||||
|
||||
// Only include value if it's not a secret
|
||||
if !sc.IsSecret {
|
||||
info.Value = sc.Value
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
// GetStringValue returns the configuration value as a string
|
||||
func (sc *SystemConfig) GetStringValue() string {
|
||||
if sc.Value != "" {
|
||||
return sc.Value
|
||||
}
|
||||
return sc.DefaultValue
|
||||
}
|
||||
|
||||
// GetIntValue returns the configuration value as an integer
|
||||
func (sc *SystemConfig) GetIntValue() (int, error) {
|
||||
value := sc.GetStringValue()
|
||||
return strconv.Atoi(value)
|
||||
}
|
||||
|
||||
// GetBoolValue returns the configuration value as a boolean
|
||||
func (sc *SystemConfig) GetBoolValue() (bool, error) {
|
||||
value := sc.GetStringValue()
|
||||
return strconv.ParseBool(value)
|
||||
}
|
||||
|
||||
// GetFloatValue returns the configuration value as a float64
|
||||
func (sc *SystemConfig) GetFloatValue() (float64, error) {
|
||||
value := sc.GetStringValue()
|
||||
return strconv.ParseFloat(value, 64)
|
||||
}
|
||||
|
||||
// SetValue sets the configuration value with type validation
|
||||
func (sc *SystemConfig) SetValue(value string) error {
|
||||
if err := sc.ValidateValue(value); err != nil {
|
||||
return err
|
||||
}
|
||||
sc.Value = value
|
||||
sc.DateModified = time.Now().UTC().Format(time.RFC3339)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetToDefault resets the configuration value to its default
|
||||
func (sc *SystemConfig) ResetToDefault() {
|
||||
sc.Value = sc.DefaultValue
|
||||
sc.DateModified = time.Now().UTC().Format(time.RFC3339)
|
||||
}
|
||||
|
||||
// isValidConfigKey validates configuration key format
|
||||
func isValidConfigKey(key string) bool {
|
||||
// Allow letters, numbers, dots, underscores, and hyphens
|
||||
for _, char := range key {
|
||||
if !((char >= 'a' && char <= 'z') ||
|
||||
(char >= 'A' && char <= 'Z') ||
|
||||
(char >= '0' && char <= '9') ||
|
||||
char == '.' || char == '_' || char == '-') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// isValidDataType validates the data type
|
||||
func isValidDataType(dataType string) bool {
|
||||
validTypes := []string{"string", "integer", "boolean", "json"}
|
||||
for _, validType := range validTypes {
|
||||
if dataType == validType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Common system configuration categories
|
||||
const (
|
||||
ConfigCategoryGeneral = "general"
|
||||
ConfigCategorySecurity = "security"
|
||||
ConfigCategoryEmail = "email"
|
||||
ConfigCategoryAPI = "api"
|
||||
ConfigCategoryLogging = "logging"
|
||||
ConfigCategoryStorage = "storage"
|
||||
ConfigCategoryCache = "cache"
|
||||
)
|
||||
|
||||
// Common system configuration keys
|
||||
const (
|
||||
ConfigKeyAppName = "app.name"
|
||||
ConfigKeyAppVersion = "app.version"
|
||||
ConfigKeyAppDescription = "app.description"
|
||||
ConfigKeyJWTExpiryHours = "security.jwt_expiry_hours"
|
||||
ConfigKeyPasswordMinLength = "security.password_min_length"
|
||||
ConfigKeyMaxLoginAttempts = "security.max_login_attempts"
|
||||
ConfigKeyLockoutDurationMinutes = "security.lockout_duration_minutes"
|
||||
ConfigKeySessionTimeoutMinutes = "security.session_timeout_minutes"
|
||||
ConfigKeyRateLimitRequests = "security.rate_limit_requests"
|
||||
ConfigKeyRateLimitWindow = "security.rate_limit_window_minutes"
|
||||
ConfigKeyLogLevel = "logging.level"
|
||||
ConfigKeyLogRetentionDays = "logging.retention_days"
|
||||
ConfigKeyMaxFileUploadSize = "storage.max_file_upload_size_mb"
|
||||
ConfigKeyCacheEnabled = "cache.enabled"
|
||||
ConfigKeyCacheTTLMinutes = "cache.ttl_minutes"
|
||||
)
|
||||
Reference in New Issue
Block a user