Files
backend_v2/scripts/seed_users/main.go
toom1996 299fd974df updae
2026-09-21 19:19:03 +08:00

108 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Command seed_users 预置内部账号(运营/编辑用,不开放公开注册)。
//
// 项目表结构由 cmd/dbtool 导出的 SQL 维护(dbtool dump → psql -f),服务启动时不再自动建表;
// 本脚本为「尚未灌库时也能独立跑」保留一份 users 兜底建表,再 upsert 一个内部账号。
//
// 用法:
// go run ./scripts/seed_users
// SEED_ADMIN_PASSWORD='你的强密码' go run ./scripts/seed_users
//
// 默认账号 admin / admin@studio.local,密码取环境变量 SEED_ADMIN_PASSWORD,
// 缺省回落强密码常量。生产部署请务必通过环境变量指定并尽快修改。
package main
import (
"errors"
"flag"
"log"
"os"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
"fashionapi/internal/config"
"fashionapi/internal/database"
"fashionapi/internal/model"
)
func main() {
configPath := flag.String("config", "", "配置文件路径,默认查找 configs/config.yml")
flag.Parse()
cfg, err := config.Load(*configPath)
if err != nil {
log.Fatalf("✗ 加载配置失败: %v", err)
}
db, err := database.New(cfg.Database)
if err != nil {
log.Fatalf("✗ 连接数据库失败: %v", err)
}
defer func() {
if e := database.Close(db); e != nil {
log.Printf("! 关闭数据库连接失败: %v", e)
}
}()
// 1. 兜底建表(与 User 模型保持一致;正式结构由 dbtool dump 的 SQL 创建,此处仅作独立运行兜底)
createSQL := `CREATE TABLE IF NOT EXISTS users (
id bigserial PRIMARY KEY,
created_at bigint NOT NULL DEFAULT 0,
updated_at bigint NOT NULL DEFAULT 0,
username varchar(64) NOT NULL,
email varchar(191) NOT NULL,
password_hash varchar(255) NOT NULL DEFAULT '',
is_deleted smallint NOT NULL DEFAULT 0,
tier varchar(16) NOT NULL DEFAULT 'free',
UNIQUE (username),
UNIQUE (email)
);`
if e := db.Exec(createSQL).Error; e != nil {
log.Fatalf("✗ 建表失败: %v", e)
}
log.Println("✓ users 表就绪")
// 2. 预置内部账号
// admin: 正式内部账号,密码取环境变量 SEED_ADMIN_PASSWORD(缺省回落强密码常量)。
// root: 测试账号,固定弱密码 root,仅供本地联调使用,勿用于生产。
adminPassword := os.Getenv("SEED_ADMIN_PASSWORD")
if adminPassword == "" {
adminPassword = "Studio#2026!Admin"
}
accounts := []struct {
username string
email string
password string
}{
{username: "admin", email: "admin@studio.local", password: adminPassword},
{username: "root", email: "root@studio.local", password: "root"},
}
for _, acc := range accounts {
hash, e := bcrypt.GenerateFromPassword([]byte(acc.password), bcrypt.DefaultCost)
if e != nil {
log.Fatalf("✗ 生成密码哈希失败(%s): %v", acc.username, e)
}
var existing model.User
qerr := db.Where("username = ?", acc.username).First(&existing).Error
switch {
case errors.Is(qerr, gorm.ErrRecordNotFound):
user := model.User{Username: acc.username, Email: acc.email, PasswordHash: string(hash)}
if cerr := db.Create(&user).Error; cerr != nil {
log.Fatalf("✗ 创建内部账号失败(%s): %v", acc.username, cerr)
}
log.Printf("✓ 已创建内部账号: %s / %s", acc.username, acc.email)
case qerr != nil:
log.Fatalf("✗ 查询账号失败(%s): %v", acc.username, qerr)
default:
existing.PasswordHash = string(hash)
if uerr := db.Save(&existing).Error; uerr != nil {
log.Fatalf("✗ 更新账号密码失败(%s): %v", acc.username, uerr)
}
log.Printf("✓ 内部账号已存在,已刷新密码哈希: %s", acc.username)
}
log.Printf("ℹ 账号 %s 登录方式: %s / 密码: %s", acc.username, acc.username, acc.password)
}
log.Println("⚠ admin 为强密码账号请尽快改默认密码;root 为弱密码测试账号,仅本地使用")
}