110 lines
2.7 KiB
Go
110 lines
2.7 KiB
Go
package database
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
"social-raiting.nekiiinkognito.ru/internal/config"
|
|
"social-raiting.nekiiinkognito.ru/internal/models"
|
|
|
|
"gorm.io/driver/mysql"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
func Connect(cfg config.Config) *gorm.DB {
|
|
dsn := fmt.Sprintf(
|
|
"%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
|
cfg.DBUser,
|
|
cfg.DBPassword,
|
|
cfg.DBHost,
|
|
cfg.DBPort,
|
|
cfg.DBName,
|
|
)
|
|
|
|
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
|
if err != nil {
|
|
log.Fatalf("failed to connect to mysql: %v", err)
|
|
}
|
|
|
|
sqlDB, err := db.DB()
|
|
if err != nil {
|
|
log.Fatalf("failed to create sql database handle: %v", err)
|
|
}
|
|
|
|
sqlDB.SetConnMaxLifetime(5 * time.Minute)
|
|
sqlDB.SetMaxIdleConns(10)
|
|
sqlDB.SetMaxOpenConns(25)
|
|
|
|
if err := sqlDB.Ping(); err != nil {
|
|
log.Fatalf("failed to ping mysql: %v", err)
|
|
}
|
|
|
|
if err := db.AutoMigrate(&models.User{}); err != nil {
|
|
log.Fatalf("failed to migrate database: %v", err)
|
|
}
|
|
|
|
if err := db.AutoMigrate(&models.UserSocialRating{}, &models.SocialRatingOperation{}); err != nil {
|
|
log.Fatalf("failed to migrate database: %v", err)
|
|
}
|
|
|
|
ensureDefaultAdmin(db, cfg)
|
|
|
|
return db
|
|
}
|
|
|
|
func ensureDefaultAdmin(db *gorm.DB, cfg config.Config) {
|
|
email := strings.ToLower(strings.TrimSpace(cfg.DefaultAdminEmail))
|
|
password := strings.TrimSpace(cfg.DefaultAdminPassword)
|
|
if email == "" || password == "" {
|
|
log.Println("skipping default admin bootstrap because admin credentials are empty")
|
|
return
|
|
}
|
|
|
|
var user models.User
|
|
err := db.Where("email = ?", email).First(&user).Error
|
|
if err == nil {
|
|
if !user.IsAdmin {
|
|
if updateErr := db.Model(&user).Update("is_admin", true).Error; updateErr != nil {
|
|
log.Fatalf("failed to promote default admin user: %v", updateErr)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
log.Fatalf("failed to check default admin user: %v", err)
|
|
}
|
|
|
|
passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
log.Fatalf("failed to hash default admin password: %v", err)
|
|
}
|
|
|
|
user = models.User{
|
|
Email: email,
|
|
PasswordHash: string(passwordHash),
|
|
IsAdmin: true,
|
|
}
|
|
if err := db.Clauses(clause.OnConflict{
|
|
Columns: []clause.Column{{Name: "email"}},
|
|
DoNothing: true,
|
|
}).Create(&user).Error; err != nil {
|
|
log.Fatalf("failed to create default admin user: %v", err)
|
|
}
|
|
|
|
if err := db.Where("email = ?", email).First(&user).Error; err != nil {
|
|
log.Fatalf("failed to load default admin user after bootstrap: %v", err)
|
|
}
|
|
|
|
if !user.IsAdmin {
|
|
if err := db.Model(&user).Update("is_admin", true).Error; err != nil {
|
|
log.Fatalf("failed to ensure default admin privileges: %v", err)
|
|
}
|
|
}
|
|
}
|