321 lines
8.1 KiB
Go
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
|
|
}
|