package model import ( "encoding/json" "errors" "strings" "gorm.io/gorm" ) // Integration represents a third-party integration configuration type Integration struct { BaseModel ProjectID string `json:"project_id" gorm:"not null;type:uuid;index;references:projects(id);onDelete:CASCADE"` Type string `json:"type" gorm:"not null;type:varchar(50)"` Config json.RawMessage `json:"config" gorm:"type:jsonb;not null"` Project Project `json:"project,omitempty" gorm:"foreignKey:ProjectID"` } // IntegrationCreateRequest represents the request to create a new integration type IntegrationCreateRequest struct { ProjectID string `json:"project_id" validate:"required,uuid"` Type string `json:"type" validate:"required,min=1,max=50"` Config map[string]interface{} `json:"config" validate:"required"` } // IntegrationUpdateRequest represents the request to update an integration type IntegrationUpdateRequest struct { Config map[string]interface{} `json:"config" validate:"required"` } // IntegrationInfo represents public integration information type IntegrationInfo struct { ID string `json:"id"` ProjectID string `json:"project_id"` Type string `json:"type"` Config map[string]interface{} `json:"config"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // BeforeCreate is called before creating an integration func (i *Integration) BeforeCreate(tx *gorm.DB) error { i.BaseModel.BeforeCreate() // Normalize type i.Type = strings.ToLower(strings.TrimSpace(i.Type)) return i.Validate() } // BeforeUpdate is called before updating an integration func (i *Integration) BeforeUpdate(tx *gorm.DB) error { i.BaseModel.BeforeUpdate() // Normalize type if it's being updated if i.Type != "" { i.Type = strings.ToLower(strings.TrimSpace(i.Type)) } return i.Validate() } // Validate validates integration data func (i *Integration) Validate() error { if i.ProjectID == "" { return errors.New("project_id is required") } if i.Type == "" { return errors.New("type is required") } if len(i.Type) > 50 { return errors.New("type must not exceed 50 characters") } if len(i.Config) == 0 { return errors.New("config is required") } // Validate that config is valid JSON var configMap map[string]interface{} if err := json.Unmarshal(i.Config, &configMap); err != nil { return errors.New("config must be valid JSON") } return nil } // ToIntegrationInfo converts Integration to IntegrationInfo (public information) func (i *Integration) ToIntegrationInfo() IntegrationInfo { integrationInfo := IntegrationInfo{ ID: i.ID, ProjectID: i.ProjectID, Type: i.Type, CreatedAt: i.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), UpdatedAt: i.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"), } // Parse config JSON to map var configMap map[string]interface{} if err := json.Unmarshal(i.Config, &configMap); err == nil { integrationInfo.Config = configMap } return integrationInfo } // SetConfig sets the configuration from a map func (i *Integration) SetConfig(config map[string]interface{}) error { configJSON, err := json.Marshal(config) if err != nil { return err } i.Config = configJSON return nil } // GetConfig gets the configuration as a map func (i *Integration) GetConfig() (map[string]interface{}, error) { var configMap map[string]interface{} err := json.Unmarshal(i.Config, &configMap) return configMap, err } // GetConfigValue gets a specific configuration value func (i *Integration) GetConfigValue(key string) (interface{}, error) { configMap, err := i.GetConfig() if err != nil { return nil, err } return configMap[key], nil } // SetConfigValue sets a specific configuration value func (i *Integration) SetConfigValue(key string, value interface{}) error { configMap, err := i.GetConfig() if err != nil { return err } configMap[key] = value return i.SetConfig(configMap) }