From 8b71f581c9ad2953c72cb6cb3cb8fd99b4d4acea Mon Sep 17 00:00:00 2001 From: kelyn Date: Sun, 31 May 2026 20:51:41 -0500 Subject: [PATCH] seed superuser on migrate --- cmd/server/main.go | 2 +- go.mod | 1 + go.sum | 2 ++ pkg/config/config.go | 7 +++++++ pkg/database/db.go | 48 +++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index 5d59243..838dbe5 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -32,7 +32,7 @@ func main() { log.Panic(err.Error()) } - if err := database.Migrate(db); err != nil { + if err := database.Migrate(db, cfg.SuperUser); err != nil { log.Panic(err.Error()) } diff --git a/go.mod b/go.mod index 2c62171..baf39cf 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,7 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.71.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/crypto v0.52.0 // indirect golang.org/x/sync v0.20.0 // indirect golang.org/x/sys v0.45.0 // indirect golang.org/x/text v0.37.0 // indirect diff --git a/go.sum b/go.sum index ebf997a..d1eaa60 100644 --- a/go.sum +++ b/go.sum @@ -76,6 +76,8 @@ github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZ github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= diff --git a/pkg/config/config.go b/pkg/config/config.go index c638eb2..ae2d40d 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -6,12 +6,19 @@ import ( "github.com/spf13/viper" ) +type User struct { + Name string `mapstructure:"name"` + Email string `mapstructure:"email"` + Password string `mapstructure:"password"` +} + type Config struct { DBDriver string `mapstructure:"db_driver"` DBConnString string `mapstructure:"db_conn_string"` JWTSecret string `mapstructure:"jwt_secret"` SessionSecret string `mapstructure:"session_secret"` ServerPort int `mapstructure:"server_port"` + SuperUser User `mapstructure:"superuser"` } func Load(path string) (*Config, error) { diff --git a/pkg/database/db.go b/pkg/database/db.go index 8ddbcea..15ed9e7 100644 --- a/pkg/database/db.go +++ b/pkg/database/db.go @@ -3,12 +3,14 @@ package database import ( "fmt" + "github.com/Henelik/cms/pkg/config" + "golang.org/x/crypto/bcrypt" "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" ) -func Migrate(db *gorm.DB) error { +func Migrate(db *gorm.DB, su config.User) error { if err := db.AutoMigrate(&User{}, &Role{}); err != nil { return fmt.Errorf("auto-migrate: %w", err) } @@ -27,6 +29,50 @@ func Migrate(db *gorm.DB) error { } } + if su.Name != "" && su.Email != "" && su.Password != "" { + if err := seedSuperUser(db, su); err != nil { + return fmt.Errorf("seed superuser: %w", err) + } + } + + return nil +} + +func seedSuperUser(db *gorm.DB, su config.User) error { + hash, err := bcrypt.GenerateFromPassword([]byte(su.Password), bcrypt.DefaultCost) + if err != nil { + return fmt.Errorf("hash password: %w", err) + } + + user := User{ + Name: su.Name, + Email: su.Email, + PasswordHash: string(hash), + } + + if err := db.FirstOrCreate(&user, User{Email: su.Email}).Error; err != nil { + return fmt.Errorf("create user: %w", err) + } + + var superadmin Role + if err := db.First(&superadmin, "name = ?", "superadmin").Error; err != nil { + return fmt.Errorf("find superadmin role: %w", err) + } + + // Check if user already has the superadmin role + var count int64 + if err := db.Table("user_roles"). + Where("user_id = ? AND role_id = ?", user.ID, superadmin.ID). + Count(&count).Error; err != nil { + return fmt.Errorf("check role association: %w", err) + } + + if count == 0 { + if err := db.Model(&user).Association("Roles").Append(&superadmin); err != nil { + return fmt.Errorf("assign superadmin role: %w", err) + } + } + return nil }