feat(backend): unified response helpers, refresh token, security hardening
- new resp package (OK/Page/Fail/BadRequest/.../InternalErr): unified error
envelope {detail, code?}, sanitized 500s (full error logged server-side,
generic message to client - stops DB error leakage), pagination envelope
{items,total,page,page_size}; migrate 200+ inline c.JSON error sites
- refresh token: 7d rotation tokens (SHA-256 hashed at rest), public
POST /auth/refresh with single-use rotation, POST /auth/logout revokes
all user refresh tokens (endpoint previously missing - frontend 404)
- security: gh-ost command line password masked in task status payload;
Instance.MarshalJSON guarantees encrypted passwords never leave the API
(removes reliance on per-handler manual masking); production (DEBUG=false)
with default JWT secret now auto-generates and persists a random secret
- safe.Go recover wrapper for background goroutines (instance probe,
gh-ost async)
- delete dead service layer (zero callers)
- fix pre-existing go vet unkeyed bson.E literals
This commit is contained in:
1 parent
d5b8b8116c
commit
16f1f7d65f
26 files changed
+916
-963
No files matched your search
+190
-165
@@ -2,6 +2,7 @@ package model
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
@@ -10,21 +11,21 @@ import (
|
||||
// ==================== User ====================
|
||||
|
||||
type User struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
Username string `gorm:"size:50;uniqueIndex;not null" json:"username"`
|
||||
DisplayName string `gorm:"size:100;not null" json:"display_name"`
|
||||
Email *string `gorm:"size:100" json:"email"`
|
||||
Phone *string `gorm:"size:20" json:"phone"`
|
||||
HashedPassword string `gorm:"size:200;not null" json:"-"`
|
||||
AuthSource string `gorm:"size:20;default:'local'" json:"auth_source"` // local / ldap
|
||||
Role string `gorm:"size:20;not null" json:"role"` // admin, dba, developer, auditor
|
||||
IsActive *bool `gorm:"default:true" json:"is_active"`
|
||||
Preferences *string `gorm:"type:text" json:"preferences"` // JSON: {"theme":"system","login_style":"split"}
|
||||
LastLogin *time.Time `json:"last_login"`
|
||||
FailedLoginAttempts int `gorm:"default:0" json:"failed_login_attempts"`
|
||||
LockedUntil *time.Time `json:"locked_until"`
|
||||
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
Username string `gorm:"size:50;uniqueIndex;not null" json:"username"`
|
||||
DisplayName string `gorm:"size:100;not null" json:"display_name"`
|
||||
Email *string `gorm:"size:100" json:"email"`
|
||||
Phone *string `gorm:"size:20" json:"phone"`
|
||||
HashedPassword string `gorm:"size:200;not null" json:"-"`
|
||||
AuthSource string `gorm:"size:20;default:'local'" json:"auth_source"` // local / ldap
|
||||
Role string `gorm:"size:20;not null" json:"role"` // admin, dba, developer, auditor
|
||||
IsActive *bool `gorm:"default:true" json:"is_active"`
|
||||
Preferences *string `gorm:"type:text" json:"preferences"` // JSON: {"theme":"system","login_style":"split"}
|
||||
LastLogin *time.Time `json:"last_login"`
|
||||
FailedLoginAttempts int `gorm:"default:0" json:"failed_login_attempts"`
|
||||
LockedUntil *time.Time `json:"locked_until"`
|
||||
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (User) TableName() string { return "users" }
|
||||
@@ -32,57 +33,66 @@ func (User) TableName() string { return "users" }
|
||||
// ==================== Instance ====================
|
||||
|
||||
type Instance struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"size:100;not null" json:"name"`
|
||||
DBType string `gorm:"size:20;not null" json:"db_type"`
|
||||
Host string `gorm:"size:200;not null" json:"host"`
|
||||
Port int `gorm:"not null" json:"port"`
|
||||
Username string `gorm:"size:100;not null" json:"username"`
|
||||
Password string `gorm:"size:500;not null" json:"password,omitempty"`
|
||||
Database *string `gorm:"size:100" json:"database"`
|
||||
Env *string `gorm:"size:20" json:"env"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
Status *string `gorm:"size:20" json:"status"`
|
||||
Version *string `gorm:"size:50" json:"version"`
|
||||
ClusterMode *bool `gorm:"default:false" json:"cluster_mode"`
|
||||
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||
AccessMode *string `gorm:"size:20;default:readwrite" json:"access_mode"`
|
||||
Workflow *string `gorm:"type:text" json:"workflow"`
|
||||
ExcludedDatabases *string `gorm:"type:text" json:"excluded_databases"`
|
||||
MaskFields *string `gorm:"type:text" json:"mask_fields"`
|
||||
GroupID *int `json:"group_id"`
|
||||
WorkflowID *int `json:"workflow_id"`
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"size:100;not null" json:"name"`
|
||||
DBType string `gorm:"size:20;not null" json:"db_type"`
|
||||
Host string `gorm:"size:200;not null" json:"host"`
|
||||
Port int `gorm:"not null" json:"port"`
|
||||
Username string `gorm:"size:100;not null" json:"username"`
|
||||
Password string `gorm:"size:500;not null" json:"password,omitempty"`
|
||||
Database *string `gorm:"size:100" json:"database"`
|
||||
Env *string `gorm:"size:20" json:"env"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
Status *string `gorm:"size:20" json:"status"`
|
||||
Version *string `gorm:"size:50" json:"version"`
|
||||
ClusterMode *bool `gorm:"default:false" json:"cluster_mode"`
|
||||
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||
AccessMode *string `gorm:"size:20;default:readwrite" json:"access_mode"`
|
||||
Workflow *string `gorm:"type:text" json:"workflow"`
|
||||
ExcludedDatabases *string `gorm:"type:text" json:"excluded_databases"`
|
||||
MaskFields *string `gorm:"type:text" json:"mask_fields"`
|
||||
GroupID *int `json:"group_id"`
|
||||
WorkflowID *int `json:"workflow_id"`
|
||||
}
|
||||
|
||||
func (Instance) TableName() string { return "instances" }
|
||||
|
||||
// MarshalJSON 保证实例密文密码在任何响应中都不出站,
|
||||
// 消除各 handler 手动遮蔽遗漏的隐患(入站绑定不受影响)。
|
||||
func (i Instance) MarshalJSON() ([]byte, error) {
|
||||
type instanceAlias Instance
|
||||
a := instanceAlias(i)
|
||||
a.Password = ""
|
||||
return json.Marshal(a)
|
||||
}
|
||||
|
||||
// ==================== Ticket ====================
|
||||
|
||||
type Ticket struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
Title string `gorm:"size:200;not null" json:"title"`
|
||||
DBType string `gorm:"size:20;not null" json:"db_type"`
|
||||
InstanceID int `gorm:"not null" json:"instance_id"`
|
||||
TargetDatabase string `gorm:"size:100;not null" json:"target_database"`
|
||||
SQLContent string `gorm:"type:text;not null" json:"sql_content"`
|
||||
RollbackSQL *string `gorm:"type:text" json:"rollback_sql"`
|
||||
Status *string `gorm:"size:20" json:"status"`
|
||||
Priority *string `gorm:"size:10" json:"priority"`
|
||||
ApplicantID int `gorm:"not null" json:"applicant_id"`
|
||||
ApproverID *int `json:"approver_id"`
|
||||
Reason *string `gorm:"type:text" json:"reason"`
|
||||
AuditResult *string `gorm:"type:text" json:"audit_result"`
|
||||
ExecuteResult *string `gorm:"type:text" json:"execute_result"`
|
||||
CreateTime time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"create_time"`
|
||||
ReviewTime *time.Time `json:"review_time"`
|
||||
ExecuteTime *time.Time `json:"execute_time"`
|
||||
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||
TicketNo *string `gorm:"size:20" json:"ticket_no"`
|
||||
ScheduledAt sql.NullTime `json:"scheduled_at"`
|
||||
WorkflowID *int `json:"workflow_id"`
|
||||
RiskLevel *string `gorm:"size:20;default:low" json:"risk_level"`
|
||||
ExecStrategy *string `gorm:"size:20;default:stop_on_error" json:"exec_strategy"`
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
Title string `gorm:"size:200;not null" json:"title"`
|
||||
DBType string `gorm:"size:20;not null" json:"db_type"`
|
||||
InstanceID int `gorm:"not null" json:"instance_id"`
|
||||
TargetDatabase string `gorm:"size:100;not null" json:"target_database"`
|
||||
SQLContent string `gorm:"type:text;not null" json:"sql_content"`
|
||||
RollbackSQL *string `gorm:"type:text" json:"rollback_sql"`
|
||||
Status *string `gorm:"size:20" json:"status"`
|
||||
Priority *string `gorm:"size:10" json:"priority"`
|
||||
ApplicantID int `gorm:"not null" json:"applicant_id"`
|
||||
ApproverID *int `json:"approver_id"`
|
||||
Reason *string `gorm:"type:text" json:"reason"`
|
||||
AuditResult *string `gorm:"type:text" json:"audit_result"`
|
||||
ExecuteResult *string `gorm:"type:text" json:"execute_result"`
|
||||
CreateTime time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"create_time"`
|
||||
ReviewTime *time.Time `json:"review_time"`
|
||||
ExecuteTime *time.Time `json:"execute_time"`
|
||||
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||
TicketNo *string `gorm:"size:20" json:"ticket_no"`
|
||||
ScheduledAt sql.NullTime `json:"scheduled_at"`
|
||||
WorkflowID *int `json:"workflow_id"`
|
||||
RiskLevel *string `gorm:"size:20;default:low" json:"risk_level"`
|
||||
ExecStrategy *string `gorm:"size:20;default:stop_on_error" json:"exec_strategy"`
|
||||
}
|
||||
|
||||
func (Ticket) TableName() string { return "tickets" }
|
||||
@@ -90,24 +100,24 @@ func (Ticket) TableName() string { return "tickets" }
|
||||
// ==================== TicketApproval ====================
|
||||
|
||||
type TicketApproval struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
TicketID int `gorm:"not null" json:"ticket_id"`
|
||||
WorkflowID *int `json:"workflow_id"`
|
||||
VersionID *int `json:"version_id"`
|
||||
StepNumber int `gorm:"not null" json:"step_number"`
|
||||
StepName *string `gorm:"size:100" json:"step_name"`
|
||||
StepType *string `gorm:"size:20" json:"step_type"`
|
||||
ApproverID *int `json:"approver_id"`
|
||||
ApproverRole *string `gorm:"size:20" json:"approver_role"`
|
||||
ActualApproverID *int `json:"actual_approver_id"`
|
||||
Action *string `gorm:"size:20" json:"action"`
|
||||
Comment *string `gorm:"type:text" json:"comment"`
|
||||
TransferFrom *int `json:"transfer_from"`
|
||||
TransferReason *string `gorm:"type:text" json:"transfer_reason"`
|
||||
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||
CompletedAt *time.Time `json:"completed_at"`
|
||||
IsTimeout *bool `json:"is_timeout"`
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
TicketID int `gorm:"not null" json:"ticket_id"`
|
||||
WorkflowID *int `json:"workflow_id"`
|
||||
VersionID *int `json:"version_id"`
|
||||
StepNumber int `gorm:"not null" json:"step_number"`
|
||||
StepName *string `gorm:"size:100" json:"step_name"`
|
||||
StepType *string `gorm:"size:20" json:"step_type"`
|
||||
ApproverID *int `json:"approver_id"`
|
||||
ApproverRole *string `gorm:"size:20" json:"approver_role"`
|
||||
ActualApproverID *int `json:"actual_approver_id"`
|
||||
Action *string `gorm:"size:20" json:"action"`
|
||||
Comment *string `gorm:"type:text" json:"comment"`
|
||||
TransferFrom *int `json:"transfer_from"`
|
||||
TransferReason *string `gorm:"type:text" json:"transfer_reason"`
|
||||
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||
CompletedAt *time.Time `json:"completed_at"`
|
||||
IsTimeout *bool `json:"is_timeout"`
|
||||
TimeoutHandledAt *time.Time `json:"timeout_handled_at"`
|
||||
}
|
||||
|
||||
@@ -116,18 +126,18 @@ func (TicketApproval) TableName() string { return "ticket_approvals" }
|
||||
// ==================== TicketSQLItem ====================
|
||||
|
||||
type TicketSQLItem struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
TicketID int `gorm:"not null" json:"ticket_id"`
|
||||
Seq int `gorm:"not null" json:"seq"`
|
||||
SQLText string `gorm:"type:text;not null" json:"sql_text"`
|
||||
SQLType *string `gorm:"size:20" json:"sql_type"`
|
||||
Status *string `gorm:"size:20;default:pending" json:"status"`
|
||||
AffectedRows *int `gorm:"default:0" json:"affected_rows"`
|
||||
DurationMs *int `gorm:"default:0" json:"duration_ms"`
|
||||
ErrorMessage *string `gorm:"type:text" json:"error_message"`
|
||||
StartedAt *time.Time `json:"started_at"`
|
||||
FinishedAt *time.Time `json:"finished_at"`
|
||||
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
TicketID int `gorm:"not null" json:"ticket_id"`
|
||||
Seq int `gorm:"not null" json:"seq"`
|
||||
SQLText string `gorm:"type:text;not null" json:"sql_text"`
|
||||
SQLType *string `gorm:"size:20" json:"sql_type"`
|
||||
Status *string `gorm:"size:20;default:pending" json:"status"`
|
||||
AffectedRows *int `gorm:"default:0" json:"affected_rows"`
|
||||
DurationMs *int `gorm:"default:0" json:"duration_ms"`
|
||||
ErrorMessage *string `gorm:"type:text" json:"error_message"`
|
||||
StartedAt *time.Time `json:"started_at"`
|
||||
FinishedAt *time.Time `json:"finished_at"`
|
||||
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||
}
|
||||
|
||||
func (TicketSQLItem) TableName() string { return "ticket_sql_items" }
|
||||
@@ -204,37 +214,37 @@ func (QueryHistory) TableName() string { return "query_histories" }
|
||||
// ==================== Workflow ====================
|
||||
|
||||
type WorkflowDefinition struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"size:100;not null" json:"name"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
Category *string `gorm:"size:50" json:"category"`
|
||||
IsDefault *bool `json:"is_default"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||
CreatedBy *int `json:"created_by"`
|
||||
FlowConfig *string `gorm:"type:json" json:"flow_config"`
|
||||
TriggerConditions *string `gorm:"type:json" json:"trigger_conditions"`
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"size:100;not null" json:"name"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
Category *string `gorm:"size:50" json:"category"`
|
||||
IsDefault *bool `json:"is_default"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||
CreatedBy *int `json:"created_by"`
|
||||
FlowConfig *string `gorm:"type:json" json:"flow_config"`
|
||||
TriggerConditions *string `gorm:"type:json" json:"trigger_conditions"`
|
||||
}
|
||||
|
||||
func (WorkflowDefinition) TableName() string { return "workflow_definitions" }
|
||||
|
||||
type WorkflowStep struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
WorkflowID int `gorm:"not null" json:"workflow_id"`
|
||||
StepNumber int `gorm:"not null" json:"step_number"`
|
||||
Name string `gorm:"size:100;not null" json:"name"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
StepType string `gorm:"size:20;not null" json:"step_type"`
|
||||
ApproverRole *string `gorm:"size:20" json:"approver_role"`
|
||||
ApproverIDs *string `gorm:"type:json" json:"approver_ids"`
|
||||
ApproverAssignment *string `gorm:"type:json" json:"approver_assignment"`
|
||||
IsRequired *bool `json:"is_required"`
|
||||
TimeoutHours *int `json:"timeout_hours"`
|
||||
AutoApproveOnTimeout *bool `json:"auto_approve_on_timeout"`
|
||||
EntryConditions *string `gorm:"type:json" json:"entry_conditions"`
|
||||
TransitionConditions *string `gorm:"type:json" json:"transition_conditions"`
|
||||
FieldPermissions *string `gorm:"type:json" json:"field_permissions"`
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
WorkflowID int `gorm:"not null" json:"workflow_id"`
|
||||
StepNumber int `gorm:"not null" json:"step_number"`
|
||||
Name string `gorm:"size:100;not null" json:"name"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
StepType string `gorm:"size:20;not null" json:"step_type"`
|
||||
ApproverRole *string `gorm:"size:20" json:"approver_role"`
|
||||
ApproverIDs *string `gorm:"type:json" json:"approver_ids"`
|
||||
ApproverAssignment *string `gorm:"type:json" json:"approver_assignment"`
|
||||
IsRequired *bool `json:"is_required"`
|
||||
TimeoutHours *int `json:"timeout_hours"`
|
||||
AutoApproveOnTimeout *bool `json:"auto_approve_on_timeout"`
|
||||
EntryConditions *string `gorm:"type:json" json:"entry_conditions"`
|
||||
TransitionConditions *string `gorm:"type:json" json:"transition_conditions"`
|
||||
FieldPermissions *string `gorm:"type:json" json:"field_permissions"`
|
||||
}
|
||||
|
||||
func (WorkflowStep) TableName() string { return "workflow_steps" }
|
||||
@@ -359,15 +369,15 @@ func (NotificationTemplate) TableName() string { return "notification_templates"
|
||||
// ==================== Other Models ====================
|
||||
|
||||
type SystemSetting struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
Key string `gorm:"size:100;not null" json:"key"`
|
||||
Value string `gorm:"type:text;not null" json:"value"`
|
||||
ValueType string `gorm:"size:20;not null" json:"value_type"`
|
||||
Group string `gorm:"size:50;not null" json:"group"`
|
||||
Label string `gorm:"size:100;not null" json:"label"`
|
||||
Desc *string `gorm:"type:text" json:"description"`
|
||||
DefaultValue *string `gorm:"type:text" json:"default_value"`
|
||||
SortOrder int `gorm:"not null" json:"sort_order"`
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
Key string `gorm:"size:100;not null" json:"key"`
|
||||
Value string `gorm:"type:text;not null" json:"value"`
|
||||
ValueType string `gorm:"size:20;not null" json:"value_type"`
|
||||
Group string `gorm:"size:50;not null" json:"group"`
|
||||
Label string `gorm:"size:100;not null" json:"label"`
|
||||
Desc *string `gorm:"type:text" json:"description"`
|
||||
DefaultValue *string `gorm:"type:text" json:"default_value"`
|
||||
SortOrder int `gorm:"not null" json:"sort_order"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
@@ -420,15 +430,15 @@ type Backup struct {
|
||||
func (Backup) TableName() string { return "backups" }
|
||||
|
||||
type SchemaRevision struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
InstanceID int `gorm:"not null" json:"instance_id"`
|
||||
Database string `gorm:"size:100;not null" json:"database"`
|
||||
Revision string `gorm:"size:64;not null" json:"revision"`
|
||||
DDLContent *string `gorm:"type:text" json:"ddl_content"`
|
||||
Checksum string `gorm:"size:64;not null" json:"checksum"`
|
||||
AppliedBy *int `json:"applied_by"`
|
||||
AppliedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"applied_at"`
|
||||
Status *string `gorm:"size:20" json:"status"`
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
InstanceID int `gorm:"not null" json:"instance_id"`
|
||||
Database string `gorm:"size:100;not null" json:"database"`
|
||||
Revision string `gorm:"size:64;not null" json:"revision"`
|
||||
DDLContent *string `gorm:"type:text" json:"ddl_content"`
|
||||
Checksum string `gorm:"size:64;not null" json:"checksum"`
|
||||
AppliedBy *int `json:"applied_by"`
|
||||
AppliedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"applied_at"`
|
||||
Status *string `gorm:"size:20" json:"status"`
|
||||
}
|
||||
|
||||
func (SchemaRevision) TableName() string { return "schema_revisions" }
|
||||
@@ -450,50 +460,64 @@ type SlowLog struct {
|
||||
func (SlowLog) TableName() string { return "slow_logs" }
|
||||
|
||||
type ScheduledTask struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"size:100;not null" json:"name"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
TaskSQLType string `gorm:"size:20;not null" json:"task_sql_type"`
|
||||
InstanceID int `gorm:"not null" json:"instance_id"`
|
||||
TargetDB *string `gorm:"size:100" json:"target_db"`
|
||||
TargetTable *string `gorm:"size:100" json:"target_table"`
|
||||
SQLContent string `gorm:"type:text;not null" json:"sql_content"`
|
||||
CronExpression string `gorm:"size:50;not null" json:"cron_expression"`
|
||||
IsEnabled *bool `json:"is_enabled"`
|
||||
LastRunAt *time.Time `json:"last_run_at"`
|
||||
LastRunStatus *string `gorm:"size:20" json:"last_run_status"`
|
||||
LastRunMessage *string `gorm:"type:text" json:"last_run_message"`
|
||||
NextRunAt *time.Time `json:"next_run_at"`
|
||||
RunCount *int `json:"run_count"`
|
||||
CreatedBy *int `json:"created_by"`
|
||||
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"size:100;not null" json:"name"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
TaskSQLType string `gorm:"size:20;not null" json:"task_sql_type"`
|
||||
InstanceID int `gorm:"not null" json:"instance_id"`
|
||||
TargetDB *string `gorm:"size:100" json:"target_db"`
|
||||
TargetTable *string `gorm:"size:100" json:"target_table"`
|
||||
SQLContent string `gorm:"type:text;not null" json:"sql_content"`
|
||||
CronExpression string `gorm:"size:50;not null" json:"cron_expression"`
|
||||
IsEnabled *bool `json:"is_enabled"`
|
||||
LastRunAt *time.Time `json:"last_run_at"`
|
||||
LastRunStatus *string `gorm:"size:20" json:"last_run_status"`
|
||||
LastRunMessage *string `gorm:"type:text" json:"last_run_message"`
|
||||
NextRunAt *time.Time `json:"next_run_at"`
|
||||
RunCount *int `json:"run_count"`
|
||||
CreatedBy *int `json:"created_by"`
|
||||
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (ScheduledTask) TableName() string { return "scheduled_tasks" }
|
||||
|
||||
type ScheduledTaskLog struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
TaskID int `gorm:"not null" json:"task_id"`
|
||||
Status string `gorm:"size:20;not null" json:"status"`
|
||||
SQLContent *string `gorm:"type:text" json:"sql_content"`
|
||||
AffectedRows *int `json:"affected_rows"`
|
||||
DurationMs *int `json:"duration_ms"`
|
||||
ErrorMessage *string `gorm:"type:text" json:"error_message"`
|
||||
StartedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"started_at"`
|
||||
FinishedAt *time.Time `json:"finished_at"`
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
TaskID int `gorm:"not null" json:"task_id"`
|
||||
Status string `gorm:"size:20;not null" json:"status"`
|
||||
SQLContent *string `gorm:"type:text" json:"sql_content"`
|
||||
AffectedRows *int `json:"affected_rows"`
|
||||
DurationMs *int `json:"duration_ms"`
|
||||
ErrorMessage *string `gorm:"type:text" json:"error_message"`
|
||||
StartedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"started_at"`
|
||||
FinishedAt *time.Time `json:"finished_at"`
|
||||
}
|
||||
|
||||
func (ScheduledTaskLog) TableName() string { return "scheduled_task_logs" }
|
||||
|
||||
type UserGroup struct {
|
||||
UserID int `gorm:"primaryKey" json:"user_id"`
|
||||
GroupID int `gorm:"primaryKey" json:"group_id"`
|
||||
UserID int `gorm:"primaryKey" json:"user_id"`
|
||||
GroupID int `gorm:"primaryKey" json:"group_id"`
|
||||
Permissions *string `gorm:"type:text" json:"permissions"`
|
||||
}
|
||||
|
||||
func (UserGroup) TableName() string { return "user_groups" }
|
||||
|
||||
// ==================== RefreshToken ====================
|
||||
|
||||
// RefreshToken 持久化 refresh token 的 SHA-256 摘要(明文不落库),支持过期与撤销。
|
||||
type RefreshToken struct {
|
||||
ID int `gorm:"primaryKey" json:"id"`
|
||||
UserID int `gorm:"index;not null" json:"user_id"`
|
||||
TokenHash string `gorm:"size:64;uniqueIndex;not null" json:"-"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
RevokedAt *time.Time `json:"revoked_at"`
|
||||
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||
}
|
||||
|
||||
func (RefreshToken) TableName() string { return "refresh_tokens" }
|
||||
|
||||
// ==================== DTO ====================
|
||||
|
||||
type LoginRequest struct {
|
||||
@@ -502,9 +526,10 @@ type LoginRequest struct {
|
||||
}
|
||||
|
||||
type LoginResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
User User `json:"user"`
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
TokenType string `json:"token_type"`
|
||||
User User `json:"user"`
|
||||
}
|
||||
|
||||
type TicketStatistics struct {
|
||||
|
||||
Reference in new issue
Block a user