test: add comprehensive test coverage and improve code quality

- Add new test files for auth, service, and handler modules
- Improve test organization and coverage
- Refactor code for better maintainability
- Add captcha, settings, stats, and theme handler tests
- Add auth module tests (CAS, OAuth, password, SSO, state)
- Add service layer tests for auth, export, permissions, roles
- All Go tests pass (exit code 0)
- All frontend tests pass (325 tests in 59 files)
This commit is contained in:
2026-04-17 20:43:50 +08:00
parent 0d66aa0423
commit 582ad7a069
136 changed files with 19010 additions and 8544 deletions

View File

@@ -7,26 +7,26 @@ type CustomFieldType int
const (
CustomFieldTypeString CustomFieldType = iota // 字符串
CustomFieldTypeNumber // 数字
CustomFieldTypeBoolean // 布尔
CustomFieldTypeDate // 日期
CustomFieldTypeNumber // 数字
CustomFieldTypeBoolean // 布尔
CustomFieldTypeDate // 日期
)
// CustomField 自定义字段定义
type CustomField struct {
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
Name string `gorm:"type:varchar(50);not null" json:"name"` // 字段名称
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
Name string `gorm:"type:varchar(50);not null" json:"name"` // 字段名称
FieldKey string `gorm:"type:varchar(50);uniqueIndex;not null" json:"field_key"` // 字段标识符
Type CustomFieldType `gorm:"type:int;not null" json:"type"` // 字段类型
Required bool `gorm:"default:false" json:"required"` // 是否必填
DefaultVal string `gorm:"type:varchar(255)" json:"default_val"` // 默认值
MinLen int `gorm:"default:0" json:"min_len"` // 最小长度(字符串)
MaxLen int `gorm:"default:255" json:"max_len"` // 最大长度(字符串)
MinVal float64 `gorm:"default:0" json:"min_val"` // 最小值(数字)
MaxVal float64 `gorm:"default:0" json:"max_val"` // 最大值(数字)
Options string `gorm:"type:varchar(500)" json:"options"` // 选项列表(逗号分隔)
Sort int `gorm:"default:0" json:"sort"` // 排序
Status int `gorm:"type:int;default:1" json:"status"` // 状态1启用 0禁用
Type CustomFieldType `gorm:"type:int;not null" json:"type"` // 字段类型
Required bool `gorm:"default:false" json:"required"` // 是否必填
DefaultVal string `gorm:"type:varchar(255)" json:"default_val"` // 默认值
MinLen int `gorm:"default:0" json:"min_len"` // 最小长度(字符串)
MaxLen int `gorm:"default:255" json:"max_len"` // 最大长度(字符串)
MinVal float64 `gorm:"default:0" json:"min_val"` // 最小值(数字)
MaxVal float64 `gorm:"default:0" json:"max_val"` // 最大值(数字)
Options string `gorm:"type:varchar(500)" json:"options"` // 选项列表(逗号分隔)
Sort int `gorm:"default:0" json:"sort"` // 排序
Status int `gorm:"type:int;default:1" json:"status"` // 状态1启用 0禁用
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
}

View File

@@ -31,7 +31,7 @@ type Device struct {
DeviceBrowser string `gorm:"type:varchar(50)" json:"device_browser"`
IP string `gorm:"type:varchar(50)" json:"ip"`
Location string `gorm:"type:varchar(100)" json:"location"`
IsTrusted bool `gorm:"default:false" json:"is_trusted"` // 是否信任该设备
IsTrusted bool `gorm:"default:false" json:"is_trusted"` // 是否信任该设备
TrustExpiresAt *time.Time `gorm:"type:datetime" json:"trust_expires_at"` // 信任过期时间
Status DeviceStatus `gorm:"type:int;default:1" json:"status"`
LastActiveTime time.Time `json:"last_active_time"`

View File

@@ -14,15 +14,15 @@ const (
// LoginLog 登录日志
type LoginLog struct {
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
UserID *int64 `gorm:"index" json:"user_id,omitempty"`
LoginType int `gorm:"not null" json:"login_type"` // 1-密码, 2-邮箱验证码, 3-手机验证码, 4-OAuth
DeviceID string `gorm:"type:varchar(100)" json:"device_id"`
IP string `gorm:"type:varchar(50)" json:"ip"`
Location string `gorm:"type:varchar(100)" json:"location"`
Status int `gorm:"not null" json:"status"` // 0-失败, 1-成功
FailReason string `gorm:"type:varchar(255)" json:"fail_reason,omitempty"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
UserID *int64 `gorm:"index;index:idx_login_logs_user_created_at" json:"user_id,omitempty"`
LoginType int `gorm:"not null" json:"login_type"` // 1-密码, 2-邮箱验证码, 3-手机验证码, 4-OAuth
DeviceID string `gorm:"type:varchar(100)" json:"device_id"`
IP string `gorm:"type:varchar(50)" json:"ip"`
Location string `gorm:"type:varchar(100)" json:"location"`
Status int `gorm:"not null" json:"status"` // 0-失败, 1-成功
FailReason string `gorm:"type:varchar(255)" json:"fail_reason,omitempty"`
CreatedAt time.Time `gorm:"autoCreateTime;index:idx_login_logs_user_created_at" json:"created_at"`
}
// TableName 指定表名

View File

@@ -18,7 +18,7 @@ type Role struct {
Description string `gorm:"type:varchar(200)" json:"description"`
ParentID *int64 `gorm:"index" json:"parent_id,omitempty"`
Level int `gorm:"default:1;index" json:"level"`
IsSystem bool `gorm:"default:false" json:"is_system"` // 是否系统角色
IsSystem bool `gorm:"default:false" json:"is_system"` // 是否系统角色
IsDefault bool `gorm:"default:false;index" json:"is_default"` // 是否默认角色
Status RoleStatus `gorm:"type:int;default:1" json:"status"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`

View File

@@ -20,8 +20,8 @@ type SocialAccount struct {
Phone string `gorm:"type:varchar(20)" json:"phone,omitempty"`
Extra ExtraData `gorm:"type:text" json:"extra,omitempty"`
Status SocialAccountStatus `gorm:"default:1" json:"status"`
CreatedAt *time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at"`
CreatedAt *time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at"`
}
func (SocialAccount) TableName() string {
@@ -63,7 +63,7 @@ type SocialAccountInfo struct {
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`
Status SocialAccountStatus `json:"status"`
CreatedAt *time.Time `json:"created_at"`
CreatedAt *time.Time `json:"created_at"`
}
func (s *SocialAccount) ToInfo() *SocialAccountInfo {

View File

@@ -4,20 +4,20 @@ import "time"
// ThemeConfig 主题配置
type ThemeConfig struct {
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
Name string `gorm:"type:varchar(50);uniqueIndex;not null" json:"name"` // 主题名称
IsDefault bool `gorm:"default:false" json:"is_default"` // 是否默认主题
LogoURL string `gorm:"type:varchar(500)" json:"logo_url"` // Logo URL
FaviconURL string `gorm:"type:varchar(500)" json:"favicon_url"` // Favicon URL
PrimaryColor string `gorm:"type:varchar(20)" json:"primary_color"` // 主色调(如 #1890ff
SecondaryColor string `gorm:"type:varchar(20)" json:"secondary_color"` // 辅助色
BackgroundColor string `gorm:"type:varchar(20)" json:"background_color"` // 背景色
TextColor string `gorm:"type:varchar(20)" json:"text_color"` // 文字颜色
CustomCSS string `gorm:"type:text" json:"custom_css"` // 自定义CSS
CustomJS string `gorm:"type:text" json:"custom_js"` // 自定义JS
Enabled bool `gorm:"default:true" json:"enabled"` // 是否启用
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
Name string `gorm:"type:varchar(50);uniqueIndex;not null" json:"name"` // 主题名称
IsDefault bool `gorm:"default:false" json:"is_default"` // 是否默认主题
LogoURL string `gorm:"type:varchar(500)" json:"logo_url"` // Logo URL
FaviconURL string `gorm:"type:varchar(500)" json:"favicon_url"` // Favicon URL
PrimaryColor string `gorm:"type:varchar(20)" json:"primary_color"` // 主色调(如 #1890ff
SecondaryColor string `gorm:"type:varchar(20)" json:"secondary_color"` // 辅助色
BackgroundColor string `gorm:"type:varchar(20)" json:"background_color"` // 背景色
TextColor string `gorm:"type:varchar(20)" json:"text_color"` // 文字颜色
CustomCSS string `gorm:"type:text" json:"custom_css"` // 自定义CSS
CustomJS string `gorm:"type:text" json:"custom_js"` // 自定义JS
Enabled bool `gorm:"default:true" json:"enabled"` // 是否启用
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
}
// TableName 指定表名
@@ -28,12 +28,12 @@ func (ThemeConfig) TableName() string {
// DefaultThemeConfig 返回默认主题配置
func DefaultThemeConfig() *ThemeConfig {
return &ThemeConfig{
Name: "default",
IsDefault: true,
PrimaryColor: "#1890ff",
SecondaryColor: "#52c41a",
Name: "default",
IsDefault: true,
PrimaryColor: "#1890ff",
SecondaryColor: "#52c41a",
BackgroundColor: "#ffffff",
TextColor: "#333333",
Enabled: true,
TextColor: "#333333",
Enabled: true,
}
}

View File

@@ -39,8 +39,8 @@ const (
// User 用户模型
type User struct {
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
Username string `gorm:"type:varchar(50);uniqueIndex;not null" json:"username"`
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
Username string `gorm:"type:varchar(50);uniqueIndex;not null" json:"username"`
// Email/Phone 使用指针类型nil 存储为 NULL允许多个用户没有邮箱/手机(唯一约束对 NULL 不生效)
Email *string `gorm:"type:varchar(100);uniqueIndex" json:"email"`
Phone *string `gorm:"type:varchar(20);uniqueIndex" json:"phone"`
@@ -51,17 +51,17 @@ type User struct {
Birthday *time.Time `gorm:"type:date" json:"birthday,omitempty"`
Region string `gorm:"type:varchar(50)" json:"region"`
Bio string `gorm:"type:varchar(500)" json:"bio"`
Status UserStatus `gorm:"type:int;default:0;index" json:"status"`
Status UserStatus `gorm:"type:int;default:0;index;index:idx_users_status_created_at" json:"status"`
LastLoginTime *time.Time `json:"last_login_time,omitempty"`
LastLoginIP string `gorm:"type:varchar(50)" json:"last_login_ip"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
CreatedAt time.Time `gorm:"autoCreateTime;index:idx_users_status_created_at" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
DeletedAt *time.Time `gorm:"index" json:"deleted_at,omitempty"`
// 2FA / TOTP 字段
TOTPEnabled bool `gorm:"default:false" json:"totp_enabled"`
TOTPSecret string `gorm:"type:varchar(64)" json:"-"` // Base32 密钥,不返回给前端
TOTPRecoveryCodes string `gorm:"type:text" json:"-"` // JSON 编码的恢复码列表
TOTPSecret string `gorm:"type:varchar(64)" json:"-"` // Base32 密钥,不返回给前端
TOTPRecoveryCodes string `gorm:"type:text" json:"-"` // JSON 编码的恢复码列表
}
// TableName 指定表名

View File

@@ -30,17 +30,17 @@ const (
// Webhook Webhook 配置
type Webhook struct {
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
Name string `gorm:"type:varchar(100);not null" json:"name"`
URL string `gorm:"type:varchar(500);not null" json:"url"`
Secret string `gorm:"type:varchar(255)" json:"-"` // HMAC 签名密钥,不返回给前端
Events string `gorm:"type:text" json:"events"` // JSON 数组,订阅的事件类型
Status WebhookStatus `gorm:"default:1" json:"status"`
MaxRetries int `gorm:"default:3" json:"max_retries"`
TimeoutSec int `gorm:"default:10" json:"timeout_sec"`
CreatedBy int64 `gorm:"index" json:"created_by"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
Name string `gorm:"type:varchar(100);not null" json:"name"`
URL string `gorm:"type:varchar(500);not null" json:"url"`
Secret string `gorm:"type:varchar(255)" json:"-"` // HMAC 签名密钥,不返回给前端
Events string `gorm:"type:text" json:"events"` // JSON 数组,订阅的事件类型
Status WebhookStatus `gorm:"default:1" json:"status"`
MaxRetries int `gorm:"default:3" json:"max_retries"`
TimeoutSec int `gorm:"default:10" json:"timeout_sec"`
CreatedBy int64 `gorm:"index" json:"created_by"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
}
// TableName 指定表名