Some checks are pending
Security Checks / security (push) Waiting to run
统一 frontend、backend、test、test-log 和 out 目录,更新构建、部署及测试入口;纳入配置管理兼容与首次安全引导修复;排除本机配置、密钥和测试产物。
83 lines
3.6 KiB
Go
83 lines
3.6 KiB
Go
package migration
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
)
|
|
|
|
func applyVerificationRetentionSchema(ctx context.Context, exec executor, dialect Dialect) error {
|
|
columns := []struct {
|
|
table string
|
|
name string
|
|
definition map[Dialect]string
|
|
}{
|
|
{table: "verification_rate_limit", name: "expires_at", definition: map[Dialect]string{
|
|
DialectSQLite: `DATETIME NOT NULL DEFAULT '1970-01-01 00:00:00'`,
|
|
DialectMySQL: `DATETIME(6) NOT NULL DEFAULT '1970-01-01 00:00:00'`,
|
|
DialectPostgres: `TIMESTAMPTZ NOT NULL DEFAULT '1970-01-01 00:00:00+00'`,
|
|
}},
|
|
{table: "verification_event", name: "expires_at", definition: map[Dialect]string{
|
|
DialectSQLite: `DATETIME NOT NULL DEFAULT '1970-01-01 00:00:00'`,
|
|
DialectMySQL: `DATETIME(6) NOT NULL DEFAULT '1970-01-01 00:00:00'`,
|
|
DialectPostgres: `TIMESTAMPTZ NOT NULL DEFAULT '1970-01-01 00:00:00+00'`,
|
|
}},
|
|
{table: "verification_event", name: "retention_class", definition: map[Dialect]string{
|
|
DialectSQLite: `TEXT NOT NULL DEFAULT 'detail'`,
|
|
DialectMySQL: `VARCHAR(16) NOT NULL DEFAULT 'detail'`,
|
|
DialectPostgres: `VARCHAR(16) NOT NULL DEFAULT 'detail'`,
|
|
}},
|
|
{table: "verification_event", name: "investigation_hold", definition: map[Dialect]string{
|
|
DialectSQLite: `INTEGER NOT NULL DEFAULT 0`,
|
|
DialectMySQL: `TINYINT NOT NULL DEFAULT 0`,
|
|
DialectPostgres: `BOOLEAN NOT NULL DEFAULT FALSE`,
|
|
}},
|
|
}
|
|
for _, column := range columns {
|
|
if err := ensureColumn(ctx, exec, dialect, column.table, column.name, column.definition[dialect]); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
updates := map[Dialect][]string{
|
|
DialectSQLite: {
|
|
`UPDATE verification_rate_limit SET expires_at = datetime(updated_at, '+30 days') WHERE expires_at = '1970-01-01 00:00:00'`,
|
|
`UPDATE verification_event SET expires_at = datetime(created_at, '+30 days') WHERE expires_at = '1970-01-01 00:00:00'`,
|
|
},
|
|
DialectMySQL: {
|
|
`UPDATE verification_rate_limit SET expires_at = DATE_ADD(updated_at, INTERVAL 30 DAY) WHERE expires_at = '1970-01-01 00:00:00'`,
|
|
`UPDATE verification_event SET expires_at = DATE_ADD(created_at, INTERVAL 30 DAY) WHERE expires_at = '1970-01-01 00:00:00'`,
|
|
},
|
|
DialectPostgres: {
|
|
`UPDATE verification_rate_limit SET expires_at = updated_at + INTERVAL '30 days' WHERE expires_at = '1970-01-01 00:00:00+00'`,
|
|
`UPDATE verification_event SET expires_at = created_at + INTERVAL '30 days' WHERE expires_at = '1970-01-01 00:00:00+00'`,
|
|
},
|
|
}
|
|
for _, statement := range updates[dialect] {
|
|
if _, err := exec.ExecContext(ctx, statement); err != nil {
|
|
return fmt.Errorf("backfill verification retention: %w", err)
|
|
}
|
|
}
|
|
|
|
return createVerificationRetentionIndexes(ctx, exec, dialect)
|
|
}
|
|
|
|
func createVerificationRetentionIndexes(ctx context.Context, exec executor, dialect Dialect) error {
|
|
statement := `CREATE INDEX IF NOT EXISTS "idx_verification_event_expires_at" ON "verification_event"("expires_at")`
|
|
if dialect == DialectMySQL {
|
|
var count int
|
|
if err := exec.QueryRowContext(ctx, "SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = ? AND index_name = ?", "verification_event", "idx_verification_event_expires_at").Scan(&count); err != nil {
|
|
return fmt.Errorf("check verification retention index: %w", err)
|
|
}
|
|
if count == 0 {
|
|
if _, err := exec.ExecContext(ctx, "CREATE INDEX `idx_verification_event_expires_at` ON `verification_event` (`expires_at`)"); err != nil {
|
|
return fmt.Errorf("create verification retention index: %w", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
if _, err := exec.ExecContext(ctx, statement); err != nil {
|
|
return fmt.Errorf("create verification retention index: %w", err)
|
|
}
|
|
return nil
|
|
}
|