package model import ( "crypto/rand" "encoding/hex" "time" "gorm.io/datatypes" "gorm.io/gorm" ) // User represents an agent/admin user in the system. type User struct { Base AccountID uint `gorm:"index;not null" json:"account_id"` Name string `gorm:"size:255;not null" json:"name"` Email string `gorm:"size:255;uniqueIndex;not null" json:"email"` Password string `gorm:"size:255;not null" json:"-"` // hashed password (bcrypt) PasswordDigest string `gorm:"size:255" json:"-"` // alias used by auth service Provider string `gorm:"size:50;default:email" json:"provider"` // email, google, saml UID string `gorm:"size:255" json:"uid,omitempty"` // external ID for OAuth providers AvatarURL string `gorm:"size:512" json:"avatar_url"` DisplayName string `gorm:"size:255" json:"display_name"` MessageSignature string `gorm:"type:text" json:"message_signature"` PubsubToken string `gorm:"size:255;uniqueIndex" json:"pubsub_token"` UISettings datatypes.JSON `gorm:"type:jsonb;default:'{}'" json:"ui_settings"` CustomAttributes datatypes.JSON `gorm:"type:jsonb;default:'{}'" json:"custom_attributes,omitempty"` Role string `gorm:"size:50;default:agent" json:"role"` // agent, admin Type string `gorm:"size:50;default:user" json:"type"` Active bool `gorm:"default:true" json:"active"` Available bool `gorm:"default:false" json:"available"` TOTPSecret string `gorm:"size:255" json:"totp_secret,omitempty"` TOTPEnabled bool `gorm:"default:false" json:"totp_enabled"` CustomRoleID *uint `gorm:"index" json:"custom_role_id,omitempty"` SignInCount int `gorm:"default:0" json:"sign_in_count"` ResetPasswordToken string `gorm:"size:255;index" json:"-"` ResetPasswordSentAt *time.Time `json:"-"` ConfirmationToken string `gorm:"size:255;index" json:"-"` ConfirmationSentAt *time.Time `json:"-"` ConfirmedAt *time.Time `json:"confirmed_at,omitempty"` LastSignInAt *time.Time `json:"last_sign_in_at,omitempty"` CurrentSignInAt *time.Time `json:"current_sign_in_at,omitempty"` } func (User) TableName() string { return "users" } // BeforeCreate mirrors Chatwoot's Pubsubable concern by assigning every user a cable token. func (u *User) BeforeCreate(tx *gorm.DB) error { if u.PubsubToken == "" { token, err := generateSecureToken(32) if err != nil { return err } u.PubsubToken = token } if u.Type == "" { u.Type = "User" } return nil } func generateSecureToken(size int) (string, error) { b := make([]byte, size) if _, err := rand.Read(b); err != nil { return "", err } return hex.EncodeToString(b), nil }