package model import ( "time" "github.com/lib/pq" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" ) type User struct { ID int64 `gorm:"primaryKey" json:"id"` Email string `gorm:"uniqueIndex;size:255;not null" json:"email"` Username string `gorm:"size:100;default:''" json:"username"` Wechat string `gorm:"size:100;default:''" json:"wechat"` Notes string `gorm:"type:text;default:''" json:"notes"` PasswordHash string `gorm:"size:255;not null" json:"-"` Role string `gorm:"size:20;default:user;not null" json:"role"` // admin/user Balance float64 `gorm:"type:decimal(20,8);default:0;not null" json:"balance"` Concurrency int `gorm:"default:5;not null" json:"concurrency"` Status string `gorm:"size:20;default:active;not null" json:"status"` // active/disabled AllowedGroups pq.Int64Array `gorm:"type:bigint[]" json:"allowed_groups"` CreatedAt time.Time `gorm:"not null" json:"created_at"` UpdatedAt time.Time `gorm:"not null" json:"updated_at"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` // 关联 ApiKeys []ApiKey `gorm:"foreignKey:UserID" json:"api_keys,omitempty"` Subscriptions []UserSubscription `gorm:"foreignKey:UserID" json:"subscriptions,omitempty"` } func (User) TableName() string { return "users" } // IsAdmin 检查是否管理员 func (u *User) IsAdmin() bool { return u.Role == "admin" } // IsActive 检查是否激活 func (u *User) IsActive() bool { return u.Status == "active" } // CanBindGroup 检查是否可以绑定指定分组 // 对于标准类型分组: // - 如果 AllowedGroups 设置了值(非空数组),只能绑定列表中的分组 // - 如果 AllowedGroups 为 nil 或空数组,可以绑定所有非专属分组 func (u *User) CanBindGroup(groupID int64, isExclusive bool) bool { // 如果设置了 allowed_groups 且不为空,只能绑定指定的分组 if len(u.AllowedGroups) > 0 { for _, id := range u.AllowedGroups { if id == groupID { return true } } return false } // 如果没有设置 allowed_groups 或为空数组,可以绑定所有非专属分组 return !isExclusive } // SetPassword 设置密码(哈希存储) func (u *User) SetPassword(password string) error { hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return err } u.PasswordHash = string(hash) return nil } // CheckPassword 验证密码 func (u *User) CheckPassword(password string) bool { err := bcrypt.CompareHashAndPassword([]byte(u.PasswordHash), []byte(password)) return err == nil }