Files
omega-server/local/utl/db/db.go
Fran Jurmanović 016728532c init bootstrap
2025-07-06 15:02:09 +02:00

321 lines
8.1 KiB
Go

package db
import (
"omega-server/local/model"
"omega-server/local/utl/logging"
"os"
"time"
"go.uber.org/dig"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
func Start(di *dig.Container) {
dbName := os.Getenv("DB_NAME")
if dbName == "" {
dbName = "app.db"
}
// Configure GORM logger
gormLogger := logger.Default
if os.Getenv("LOG_LEVEL") == "DEBUG" {
gormLogger = logger.Default.LogMode(logger.Info)
} else {
gormLogger = logger.Default.LogMode(logger.Silent)
}
db, err := gorm.Open(sqlite.Open(dbName), &gorm.Config{
Logger: gormLogger,
})
if err != nil {
logging.Panic("failed to connect database: " + err.Error())
}
// Configure connection pool
sqlDB, err := db.DB()
if err != nil {
logging.Panic("failed to get database instance: " + err.Error())
}
// Set connection pool settings
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
err = di.Provide(func() *gorm.DB {
return db
})
if err != nil {
logging.Panic("failed to bind database: " + err.Error())
}
logging.Info("Database connected successfully")
Migrate(db)
}
func Migrate(db *gorm.DB) {
logging.Info("Starting database migration...")
err := db.AutoMigrate(
&model.User{},
&model.Role{},
&model.Permission{},
&model.SystemConfig{},
&model.AuditLog{},
&model.SecurityEvent{},
)
if err != nil {
logging.Panic("failed to migrate database models: " + err.Error())
}
logging.Info("Database migration completed successfully")
Seed(db)
}
func Seed(db *gorm.DB) error {
logging.Info("Starting database seeding...")
if err := seedRoles(db); err != nil {
return err
}
if err := seedPermissions(db); err != nil {
return err
}
if err := seedDefaultAdmin(db); err != nil {
return err
}
if err := seedSystemConfigs(db); err != nil {
return err
}
logging.Info("Database seeding completed successfully")
return nil
}
func seedRoles(db *gorm.DB) error {
roles := []model.Role{
{Name: "admin", Description: "Administrator with full access"},
{Name: "user", Description: "Regular user with limited access"},
{Name: "viewer", Description: "Read-only access"},
}
for _, role := range roles {
var existingRole model.Role
err := db.Where("name = ?", role.Name).First(&existingRole).Error
if err == gorm.ErrRecordNotFound {
role.Init()
if err := db.Create(&role).Error; err != nil {
return err
}
logging.Info("Created role: %s", role.Name)
}
}
return nil
}
func seedPermissions(db *gorm.DB) error {
permissions := []model.Permission{
{Name: "user:create", Description: "Create new users"},
{Name: "user:read", Description: "Read user information"},
{Name: "user:update", Description: "Update user information"},
{Name: "user:delete", Description: "Delete users"},
{Name: "role:create", Description: "Create new roles"},
{Name: "role:read", Description: "Read role information"},
{Name: "role:update", Description: "Update role information"},
{Name: "role:delete", Description: "Delete roles"},
{Name: "system:config", Description: "Access system configuration"},
{Name: "system:logs", Description: "Access system logs"},
{Name: "system:admin", Description: "Full system administration"},
}
for _, permission := range permissions {
var existingPermission model.Permission
err := db.Where("name = ?", permission.Name).First(&existingPermission).Error
if err == gorm.ErrRecordNotFound {
permission.Init()
if err := db.Create(&permission).Error; err != nil {
return err
}
logging.Info("Created permission: %s", permission.Name)
}
}
// Assign all permissions to admin role
var adminRole model.Role
if err := db.Where("name = ?", "admin").First(&adminRole).Error; err != nil {
return err
}
var allPermissions []model.Permission
if err := db.Find(&allPermissions).Error; err != nil {
return err
}
if err := db.Model(&adminRole).Association("Permissions").Replace(allPermissions); err != nil {
return err
}
// Assign basic permissions to user role
var userRole model.Role
if err := db.Where("name = ?", "user").First(&userRole).Error; err != nil {
return err
}
var userPermissions []model.Permission
userPermissionNames := []string{"user:read", "role:read"}
if err := db.Where("name IN ?", userPermissionNames).Find(&userPermissions).Error; err != nil {
return err
}
if err := db.Model(&userRole).Association("Permissions").Replace(userPermissions); err != nil {
return err
}
// Assign read permissions to viewer role
var viewerRole model.Role
if err := db.Where("name = ?", "viewer").First(&viewerRole).Error; err != nil {
return err
}
var viewerPermissions []model.Permission
viewerPermissionNames := []string{"user:read", "role:read"}
if err := db.Where("name IN ?", viewerPermissionNames).Find(&viewerPermissions).Error; err != nil {
return err
}
if err := db.Model(&viewerRole).Association("Permissions").Replace(viewerPermissions); err != nil {
return err
}
return nil
}
func seedDefaultAdmin(db *gorm.DB) error {
// Check if admin user already exists
var existingAdmin model.User
err := db.Where("email = ?", "admin@example.com").First(&existingAdmin).Error
if err != gorm.ErrRecordNotFound {
return nil // Admin already exists or other error
}
// Get admin role
var adminRole model.Role
if err := db.Where("name = ?", "admin").First(&adminRole).Error; err != nil {
return err
}
// Create default admin user
defaultPassword := os.Getenv("DEFAULT_ADMIN_PASSWORD")
if defaultPassword == "" {
defaultPassword = "admin123"
}
admin := model.User{
Email: "admin@example.com",
Username: "admin",
Name: "System Administrator",
Active: true,
}
admin.Init()
if err := admin.SetPassword(defaultPassword); err != nil {
return err
}
if err := db.Create(&admin).Error; err != nil {
return err
}
// Assign admin role
if err := db.Model(&admin).Association("Roles").Append(&adminRole); err != nil {
return err
}
logging.Info("Created default admin user with email: %s", admin.Email)
logging.Warn("Default admin password is: %s - PLEASE CHANGE THIS IMMEDIATELY!", defaultPassword)
return nil
}
func seedSystemConfigs(db *gorm.DB) error {
configs := []model.SystemConfig{
{
Key: "app.name",
Value: "Bootstrap App",
DefaultValue: "Bootstrap App",
Description: "Application name",
Category: "general",
DataType: "string",
IsEditable: true,
DateModified: time.Now().UTC().Format(time.RFC3339),
},
{
Key: "app.version",
Value: "1.0.0",
DefaultValue: "1.0.0",
Description: "Application version",
Category: "general",
DataType: "string",
IsEditable: false,
DateModified: time.Now().UTC().Format(time.RFC3339),
},
{
Key: "security.jwt_expiry_hours",
Value: "24",
DefaultValue: "24",
Description: "JWT token expiry time in hours",
Category: "security",
DataType: "integer",
IsEditable: true,
DateModified: time.Now().UTC().Format(time.RFC3339),
},
{
Key: "security.password_min_length",
Value: "8",
DefaultValue: "8",
Description: "Minimum password length",
Category: "security",
DataType: "integer",
IsEditable: true,
DateModified: time.Now().UTC().Format(time.RFC3339),
},
{
Key: "security.max_login_attempts",
Value: "5",
DefaultValue: "5",
Description: "Maximum login attempts before lockout",
Category: "security",
DataType: "integer",
IsEditable: true,
DateModified: time.Now().UTC().Format(time.RFC3339),
},
{
Key: "security.lockout_duration_minutes",
Value: "30",
DefaultValue: "30",
Description: "Account lockout duration in minutes",
Category: "security",
DataType: "integer",
IsEditable: true,
DateModified: time.Now().UTC().Format(time.RFC3339),
},
}
for _, config := range configs {
var existingConfig model.SystemConfig
err := db.Where("key = ?", config.Key).First(&existingConfig).Error
if err == gorm.ErrRecordNotFound {
config.Init()
if err := db.Create(&config).Error; err != nil {
return err
}
logging.Info("Created system config: %s", config.Key)
}
}
return nil
}